# Quotient
Quotient is an AI-native marketing platform and intelligent agent in one — built to plan and execute campaigns across email, social, blog, and events, without the fragmented tools you've outgrown.
It combines a full-featured SaaS marketing platform (content authoring, distribution, lead storage, performance analytics) with a powerful AI agent that can operate the platform, access external tools, and manage brand knowledge and memories. Quotient gives small-to-mid-sized B2B companies — from seed to Series C — the output of a top-notch marketing agency at a fraction of the cost.
Key capabilities:
- AI agent that plans and executes full marketing campaigns end-to-end
- Email marketing with custom domains, audience targeting, and CRM sync
- Social media publishing across major platforms
- Blog content creation and WordPress publishing
- HubSpot integration for contact and list management
- Brand memory so the agent learns your voice, audience, and past campaigns
- SDK and MCP server for developers building on top of Quotient
---
# Docs
## File Tree
docs/
analytics/
custom-events/
server-side-conversions
identifying-users
on-site-tracking/
custom-website
framer
google-tag-manager
webflow
wix
wordpress
reports/
catalog
tagging-and-attribution
audience/
import-audience
location
people
segments
blog
campaign
email/
dns/
cloudflare-guide
godaddy-guide
namecheap-guide
shopify-guide
squarespace-guide
email-status
suppression
unsubscribe
variables/
conditional-components
flow
integrations/
attio/
field-mappings
setup
hubspot/
email-sync
field-mappings
lists
objects
setup
troubleshooting
slack
wordpress/
setup
syncing
troubleshooting
zoom
mcp/
connecting-tools/
github-private-repos
from-other-apps/
setup-instructions
tools-reference
navigating
plans-and-billing
sdk/
analytics
api-keys
audience
blog
flow
memory
react
social
trust-security/
privacy
subprocessors
working-with-ai/
jobs
memory
## Documentation
-- Start of: /blog
---
title: Blog
description: Write and publish blog posts with Quotient
order: 6
---
Writing a blog is one of the best ways to attract interest in your brand and establish your business as a trusted leader in its space. More specifically, a blog serves several purposes within your marketing strategy:
- **Organic SEO:** Thoughtful, SEO-optimized blogs can help your brand rank for high-intent keywords in search engines like Google. Note that this can also help your brand get noticed by AI assistants like ChatGPT.
- **Thought Leadership:** An informative, high-quality blog establishes your brand as a thought leader in your industry. This helps establish your brand’s reputation and credibility, which is critical for selling your product.
- **Content that Sells without Selling:** A blog can help educate customers and prospects about the importance of your solution. The goal of a blog is not necessarily to sell your product directly, but rather to educate and promote understanding of the problem your business is trying to solve.
With Quotient, you can write and publish a blog from the same integrated platform you use to send email, plan events, and manage your brand.
## Core Concepts
**Posts**
A blog post is an individual article with a dedicated URL. Blog posts are written as **rich text**, which means you can apply basic formatting like bold/italics, headers, and lists, but more advanced formatting like fonts and text size are controlled in your publishing environment.
**Authors and Tags**
Each blog has one or more **authors** and can also optionally have **tags**. Authors are linked to Quotient users, so if you want someone to be listed as a blog author they must be a user in Quotient.
Tags are simply for organizational purposes to help users navigate your blog. For example you might have separate tags for…
- Company Updates
- Product Updates
- Industry Trends
**SEO Metadata**
Blogs also have additional metadata for SEO, such as…
- **Meta Description:** A short summary that appears in search results and helps improve click-through rates
- **Keywords:** Target keywords that help search engines understand your content's focus
- **Thumbnail Image:** The featured image that appears when your blog is shared on social media
- **Publish Date:** Helps search engines understand when content was published
This information is not necessarily visible on the page, but it helps search engines better understand the content and signals that it's fresh and relevant.
## Writing with Quotient
You can ask Quotient to write entire blogs for you, conduct research, or edit and proofread blogs you've written.
Quotient draws on its memory of your business, which is crucial for creating on-brand, on-message content. It also reads campaign briefs, ensuring that blogs fit into larger marketing campaigns.
Here are a few tips for getting the most out of Quotient when writing blogs:
- Share samples of your writing and ask Quotient to save them to memory. This will help Quotient get a sense of your unique writing voice and preferences. Similarly, it can be helpful to put together an Author Profile for common blog authors.
- Give Quotient your rough notes or stream-of-consciousness voice messages and ask it to polish them up into a nicely formatted, professional blog post.
- Writing with Quotient is an iterative, back-and-forth process. You can ask it to draft the first version of the post, and then you can select portions of the text that you want to tweak using the “Ask for Changes” feature.
## Publishing Your Blog
Once you've written your blog, you have two options for publishing it to your website:
1. If you have a custom-built website using a framework like NextJS or Remix, you can use the Quotient Javascript SDK to fetch data from the blog and render it.
2. If you use Webflow, you can use our Webflow integration to sync blog posts from Quotient to Webflow’s CMS.
In the near future, we will be adding additional integrations to other web platforms like Framer and WordPress as well.
You can schedule your blog to publish at a specific date and time, or publish it immediately. You can also unpublish a blog after it has been published.
### Publishing Changes
Once your blog moves to the __Published__ status, it will be visible on your site.
However, you may often want to publish changes to an already-published blog. Changes you make to a published blog will **_not_** automatically sync to your website. To publish them, click the “Publish Changes” button in the upper right hand corner of the blog page.
-- End of: /blog
-- Start of: /campaign
---
title: Campaigns
description: Plan and organize your marketing into campaigns
order: 3
---
Campaigns help you organize your marketing efforts around a central theme or goal. A **[campaign](/s/most-recent-business/campaigns)** in Quotient is a coordinated collection of tasks and deliverables that work together toward a common objective. Think of campaigns as the strategic umbrella that organizes your marketing work across different channels and timeframes.
Grouping deliverables into campaigns is not a requirement in Quotient; you can still publish one-off blog posts or email broadcasts. But grouping things into campaigns helps ensure that your marketing has a consistent message, making it more effective.
Here are some examples of campaigns:
1. **New Feature Announcement:** When announcing an important new feature or launching a new product, it's common to write blogs, send email broadcasts, or host webinars promoting the new feature.
2. **Events:** Campaigns are often built around marketing events. For example, if you are hosting a webinar, or if your company is attending an industry conference, you might want to do a lot of marketing around that event, e.g. sending emails to customers before and after the event.
3. **Thought Leadership:** A specific topic, such as a new regulation or technological breakthrough, might be trending in your industry. To capitalize on interest, you might want to publish a series of blogs explaining your company's perspective on it.
## Core Concepts
### Tasks
Campaigns are organized as a series of tasks. Each task represents a specific piece of work that needs to be completed as part of the campaign. Tasks move through a workflow with four statuses:
- **To-do** - Task has been created but work hasn't started yet
- **In progress** - Task is actively being worked on
- **In review** - Task is complete and awaiting review or approval
- **Done** - Task is complete and approved
Tasks can represent many different types of work:
**Deliverable-Linked Tasks** - Work that's connected to creating specific marketing assets in Quotient:
- Writing a blog post
- Designing an email broadcast
- Setting up a marketing event
- Building an automated flow
- Creating a social media post
**Standalone Tasks** - Work that doesn't happen directly in Quotient:
- Shooting a video
- Taking screenshots of a new feature
- Getting legal approval
- Running paid ads
- Coordinating with external vendors
### Deliverables
When a task involves creating a marketing asset that will be distributed to your audience, it can be linked to a **deliverable**. Deliverables are the actual marketing assets created in Quotient:
- **Blog Posts** - Articles published on your website
- **Email Broadcasts** - Emails sent to your audience
- **Marketing Events** - Webinars, conferences, or in-person events
- **Flows** - Automated email sequences
- **Social Posts** - Content for X, LinkedIn, Instagram, Facebook, and TikTok
When you link a task to a deliverable (like "Write Q4 product announcement blog"), the task provides project management structure while the deliverable contains the actual content and publishing details.
### Briefs
Briefs are strategic memos that explain the purpose, message, and audience for a campaign. This information is critical for aligning both humans and Quotient on the strategy of a campaign. Quotient reads the brief for a campaign when creating content to ensure that the content is consistent with the theme and message of the campaign.
### Task Owners
Each task can have an **owner** - the human who's responsible for completing it. When you're the owner of a task, you'll get notifications about its progress as Quotient works on it, and you can track it on your personal task list.
## Planning Campaigns with Quotient
Ask Quotient to help you develop campaigns from inception to execution. It can create the campaign, write the initial brief, break down the work into tasks, and pick the right timeframe. Once you've agreed on the concept, Quotient will work through each task, creating the deliverables (like blogs, emails, or social posts) in new threads.
Here are some tips for getting the most out of Quotient when planning campaigns:
- You can ask Quotient to help you come up with ideas for campaigns, or if you already have a clear idea for a campaign you can ask it to break it down into actionable tasks.
- Ask Quotient to search the web and perform research, which is helpful for campaigns that have to do with current events or trending topics.
- Every company runs campaigns differently. Some prefer many small campaigns with just a few tasks and deliverables, while others prefer large campaigns with dozens of tasks and deliverables over several months. Tell Quotient about your preferred workflow and ask it to "remember" it in the future.
- If you're not happy with a campaign, tell Quotient what you'd like to change. It will update briefs and add or remove tasks until it looks right. Building campaigns is an iterative process and requires some back and forth.
-- End of: /campaign
-- Start of: /flow
---
title: Flows
description: Automate your marketing with flows that run on triggers and schedules
order: 8
---
Quotient allows you to automate common internal and external workflows throughout your marketing stack. You can easily put together automations such as…
- Sending automated sequences of marketing emails based, like a welcome series or account activation
- Sending highly personalized, AI generated emails tailored to each customer's recent activity and firmographics
- Updating a prospect's lead score when they signal high intent to purchase, e.g. by performing specific actions on your site
- Sending automated notifications to your team when a new customer signs up for your product or achieves a certain lead score
Automations like these help you engage with customers with personalized content at the right time, and they can also help automate repetitive work for your team.
## Core Concepts
**Flows**
[Flows](/s/most-recent-business/flows) are automated sequences of actions orchestrated by the Quotient platform. You can create flows using the flow editor or by chatting with Quotient. Every flow starts with a **trigger** and then proceeds through a series of **steps** until it's finished.
Flows can also optionally be scoped to a specific **segment** of people, which you can define dynamically in each flow.
**Trigger**
Triggers are events or schedules that initiate a flow. There are six different trigger types:
1. **Event Trigger:** Activates when a specific user action occurs (email subscribe, page view, add to cart, checkout complete). Responds to customer behavior.
2. **Schedule Trigger:** Runs at defined times and frequencies (daily, weekly, monthly). Used for recurring communications.
3. **Person Update Trigger:** Activates when a specific field in a customer profile changes. Can trigger on any change or only when matching a specific value.
4. **Person Created Trigger:** Activates when a new person record is added to Quotient. Used for initial contact sequences.
5. **Programmatic Trigger:** Activates via the Quotient API or SDK. Provides programmatic control over flow initiation.
6. **Marketing Event Trigger:** Activates when someone's participation status changes in a marketing event (webinar, conference). Tracks status changes like registered, attended, or no-show.
**Steps**
Once the trigger has been activated, the flow proceeds through a series of steps. There are eight different step types:
1. **Send Email:** Sends an email to the customer using a specified template. Can include dynamic variables for personalization.
2. **AI Email:** Uses artificial intelligence to dynamically decide whether to send an email and which template to use based on customer data and behavior.
3. **Delay:** Pauses the flow for a specified duration (minutes, hours, days, weeks, months). Controls timing between actions.
4. **Update Person:** Updates a field in the person's profile. Works with both standard fields and custom properties.
5. **Notify User:** Sends an internal notification to a team member. References users by USER-type fields on the person or company record.
6. **Update Lead Score:** Modifies the person's lead score using increment,
decrement, or set operations.
7. **Send to CRM:** Sends person data to connected CRM systems (Attio, Salesforce, HubSpot). Configurable for different CRM object types.
8. **HTTP Request:** Sends a custom request to any external URL, like a webhook, Zapier, or another tool in your stack. You can personalize the path, query parameters, and request body with customer data, though the destination domain itself must stay fixed.
**Conditionals**
Conditional steps create branching paths in your flow based on either profile data or random sampling. They evaluate a statement about a person and route them down one of two paths: the "if true" branch or the "if false" branch.
Conditions can be based on:
- Profile properties (location, preferences)
- Behavioral history (pages viewed, purchases made)
- Email engagement metrics
- Random sampling (for A/B testing)
Conditionals transform flows from linear sequences into adaptive journeys that respond to each person's unique attributes and behaviors, allowing for targeted messaging without creating separate flows for each scenario.
## Building Flows with Quotient
Tell Quotient the business objective of your flow and it will help fill in the details, including creating any email templates or segments needed along the way.
Here are some tips for getting the most out of Quotient when building flows:
1. If there are specific email templates you want to use in your flow, @ mention them so that Quotient knows to use them.
2. If you are using Quotient to automate workflows with your CRM, make sure to explain how your CRM is set up, e.g. any custom fields you use for lead qualification.
## Common Use Cases
Flows are a versatile tool that can support a wide range of marketing automation needs. While most commonly used for customer communication, flows can also streamline internal processes and automate data management across your marketing stack.
Let's walk through a few of the most common use cases for flows.
### Sending Email to Users
The most common use case for flows is sending automated marketing emails to users. Whereas email broadcasts send a single blast email to many people all at once, flows allow for more personalized, timely messaging that reaches customers at specific moments in their buying journey.
These flows typically leverage the **Send Email** step to deliver targeted messages, often combined with **Delay** steps to control timing and **Conditional** steps to create personalized paths based on customer behavior.
Here are some examples:
- **Welcome Series** - Automatically send a sequence of emails to new subscribers introducing your product or service, typically spaced over several days or weeks. Uses **Send Email** and **Delay** steps with an **Event** trigger for new subscribers.
- **Customer Activation** - Guide new users through key features with timely, targeted emails based on their activity (or lack thereof) in your product. Combines **Send Email** steps with **Conditional** logic to check user activity.
- **Customer Winback** - Re-engage inactive customers with personalized offers or content based on their previous purchase history and browsing behavior. Uses **Schedule** triggers with **Conditional** steps to identify inactive users.
### AI Personalized Email
AI Personalized Email steps are an especially powerful feature of flows in Quotient. These steps allow you to use AI to predict the best email to send a user based on their recent behavior - plus the instructions you provide.
This helps improve conversion rates and improve outreach to customers who may not have been addressed by more deterministic, logic-based flows.
An AI Personalized Email step accepts two main parameters:
**Instructions** - A single block of instructions you wish to provide the AI. You can give the AI whatever instructions you like here. For example:
- "Send promotional emails only to users who have opened emails in the last 30 days"
- "Prioritize product recommendations from categories the user has previously purchased"
- "Avoid sending more than 2 emails per week to any user"
**Available Templates** - A list of templates that the AI can choose from. The AI will only choose from a list of pre-approved templates for this particular flow.
Based on these, the AI will choose whether to send a template at all and, if so, which template to send.
It is common to use AI Personalized Email steps in conjunction with schedule triggers. For example you might have a flow that is triggered at 9:00 am every Monday for any users that have not opened an email in the past two weeks. In this flow you could instruct the AI to choose from a set of templates in an effort to re-engage the customer.
### Sending Data to the CRM
CRM integration flows automate the synchronization of customer data between Quotient and your CRM system, ensuring your sales and customer success teams always have access to the most current and relevant information.
These flows typically use the **Send to CRM** step to sync data with systems like Attio, Salesforce, and HubSpot, often combined with **Update Lead Score** and **Update Person** steps to track customer progression.
Here are some examples:
- **Lead Score Updates** - Automatically increment a prospect's lead score when they perform specific high-value actions like downloading resources or visiting pricing pages. Uses **Update Lead Score** steps with **Event** triggers for high-value actions.
- **Deal Stage Progression** \- Move leads through your sales pipeline based on their behavior and engagement with your marketing materials. Uses **Conditional** steps to check engagement levels before **Send to CRM** steps.
### Notifying Your Team
Quotient can also send notifications via email or Slack to your team when certain events happen. This is helpful for getting your team's attention when someone performs an action that your team should know about - e.g. a new signup or a cancellation.
These flows use the **Notify User** step to send internal notifications to team members, often triggered by **Event** or **Person Update** triggers that signal important customer actions.
- **New Account Alerts** - Notify relevant team members when a new customer signs up, including essential information about the customer's profile and initial activity. Uses **Notify User** steps with **Person Created** triggers.
- **Lead Qualification Notifications** - Alert sales representatives when a prospect reaches a specified lead score threshold or performs high-intent actions. Combines **Notify User** steps with **Person Update** triggers monitoring lead score changes.
- **Customer Milestone Notifications** - Keep customer success teams informed when accounts reach important usage milestones or when accounts show signs of churn risk. Uses **Conditional** steps to check milestone criteria before **Notify User** steps.
-- End of: /flow
-- Start of: /index
---
title: Introduction
description: Getting started with Quotient
order: 0
---
## What is Quotient?
Quotient is an **AI demand marketing platform.** "Demand marketing refers to all the activities that attract customers to your business, such as…
- Writing online content like blogs or social media posts
- Sending emails to customers or prospects
- Hosting in-person or online events like webinars and trade shows
- Building an authoritative brand that customers recognize and trust
With Quotient, you can do all of this from a single integrated platform \- write blogs and emails, plan campaigns and events, and manage your brand information, all powered by AI.
## Working with Quotient
You can chat with Quotient to get things done, just like you would with a coworker. If you've used products like ChatGPT or Claude, the experience will feel familiar. Simply tell Quotient what you want, and it takes care of the rest.
Quotient understands your brand and learns your business's preferences and workflows over time through [memory](/docs/working-with-ai/memory). You can ask it to do virtually any marketing task on the platform, from writing blog posts and composing emails to planning campaigns, building customer segments, and creating automated workflows.
## Quotient's Interface
Quotient's interface has two main parts:
1. The **app panel** \- a traditional graphical user interface where you can manage campaigns, write blogs, compose emails, etc.
2. The **chat panel** \- a conversational interface on the right side of the app panel where you can chat with Quotient.
As a general rule, everything that you can do in the app panel you can _also_ do by asking Quotient in the chat panel, and vice versa.
When you chat with Quotient, it understands what page you're on in the app panel and can "see" what you're looking at. This makes it easy to collaborate side by side, much like you would with a human coworker.
## Next Up
## For AI Agents
Every page in these docs is available as raw Markdown — just append `.md` to any URL (for example, `/docs/working-with-ai.md`).
-- End of: /index
-- Start of: /navigating
---
title: Navigating Quotient
description: How to get around the platform
order: 2
---
Quotient keeps two things side by side: your work, and a conversation about it.
There's a fair amount on screen, so here are the shortcuts and small tricks that
make moving between them feel quick instead of busy.
## The Command Menu (⌘ + K)
The fastest way to get anywhere in Quotient is the command menu. Press `⌘ + K`
(or `Ctrl + K` on Windows and Linux) from anywhere, then start typing.
The command menu does two jobs. First, it's a universal search: type the name of
an email broadcast, flow, asset, or any other object and jump straight to it.
Second, it's a launcher for actions, so instead of hunting through menus you can
run a command right from the keyboard.
What makes it powerful is that it's **contextual** — the actions it offers
depend on where you are. If you're looking at an email broadcast, you'll see
broadcast actions like "Send a Test" or "Schedule" right at the top. Open it
somewhere else and you'll get that page's actions instead.
Once it's in your muscle memory, you'll rarely take your hands off the keyboard.
When in doubt, reach for `⌘ + K`.
## @ Mentioning
When you're chatting with Quotient, you can quickly reference existing objects
by @ mentioning them — a campaign, an email broadcast, a memory, another user,
and most other things you've created.
This automatically shares all the relevant context with Quotient — like sending
a hyperlink to a human colleague instead of describing the thing from memory. So
rather than explaining which campaign you mean, just @ mention it and Quotient
has everything it needs.
## Collapsible Sidebar
Press `⌘ + .` to collapse and expand the navigation sidebar, giving your work
more room when you need it.
## Keyboard Shortcuts
If you like to move fast, Quotient has shortcuts for the things you do most
often. Here are the handiest ones:
| Action | Shortcut |
| ------------------------------- | ----------- |
| Open the command menu | `⌘ + K` |
| Start a new chat | `⌘ + /` |
| Start a new chat in full screen | `⌘ + ⇧ + /` |
| Go to the previous chat | `⌘ + ⇧ + ,` |
| Go to the next chat | `⌘ + ⇧ + .` |
| Attach a file to a message | `⌘ + U` |
And for arranging your workspace:
| Action | Shortcut |
| ------------------------- | -------------- |
| Show the chat sidebar | `Ctrl + \` |
| Make the chat full screen | `Ctrl + M` |
| Hide the chat panel | `Ctrl + ⇧ + \` |
| Move the chat left | `Ctrl + [` |
| Move the chat right | `Ctrl + ]` |
| Collapse the sidebar | `⌘ + .` |
For the complete list, press `⌘ + ;` in the app to open the keyboard shortcuts
cheat sheet. We keep it up to date as shortcuts change.
-- End of: /navigating
-- Start of: /plans-and-billing
---
title: Plans and Billing
description: How Quotient's plans, usage, billing, and trials work
order: 1050
---
Quotient offers four plans — **Free**, **Starter**, **Pro**, and **Scale** — each designed for a different stage of your marketing operation. For a side-by-side comparison of what's included in each plan, visit the [pricing page](https://www.getquotient.ai/pricing).
This document covers the details of how billing, usage, and plan changes actually work once you're up and running.
## AI Credits
AI credits are the unit of measurement for work that Quotient's AI does on your behalf. Every time Quotient writes a blog draft, composes an email, researches a competitor, or answers a question in chat, it consumes AI credits.
Not all tasks consume credits equally. A few factors affect how many credits a given interaction uses:
- **Conversation length.** Longer threads with more back-and-forth consume more credits than short, focused requests, because Quotient re-reads the full conversation each time it responds.
- **AI model.** Premium AI models (available on Starter and above) are more capable but consume more credits per interaction than the standard models available on the Free plan.
- **Task complexity.** Tasks that require Quotient to use tools — like searching the web, looking up audience data, or reading multiple documents — consume more credits than simple conversational responses, because each tool use involves additional processing.
- **Content length.** Generating a 2,000-word blog post consumes more credits than writing a short social media caption.
You can monitor your credit usage at any time in [Settings > Usage](/s/most-recent-business/settings/usage), which shows a breakdown of consumption within your current billing cycle.
## Usage and Overages
Each plan includes a monthly allotment of AI credits, emails sent, social posts published, and blog posts published. How overages are handled depends on your plan:
**Free plan.** When you reach your included allotment, usage is cut off until the next billing cycle. There are no overage charges — but you won't be able to use the feature until your usage resets.
**Paid plans (Starter, Pro, Scale).** You're never cut off. If you exceed your included allotment, you can keep using the platform and the overage is added to your next invoice. This means your monthly bill may vary slightly depending on usage, though most users stay within their included allotments.
Your usage resets at the start of each billing cycle, which is anchored to the date you first subscribed — not the first of the month.
## Resources and Feature Access
In addition to usage-based metrics, each plan includes a set number of **resources** (users and connected social accounts) and access to certain **features** (email sending, social publishing, CRM integrations, Slack, custom email domains, and premium AI models).
Resource limits are hard caps — if your plan includes 15 users, you'll need to upgrade before inviting a sixteenth. Feature access is binary: either your plan includes it or it doesn't. You can see exactly what's included on each plan on the [pricing page](https://www.getquotient.ai/pricing).
## Free Trial
Every new Quotient business starts with a **14-day free trial of the Pro plan**. During the trial, you have full access to all Pro features — CRM integrations, Slack, custom email domains, premium AI models, and the full Pro usage allotment — without entering a credit card.
When the trial ends, your business reverts to the Free plan. Any content you created during the trial (published blogs, sent emails, etc.) remains intact, but you'll lose access to Pro-only features until you subscribe.
If you subscribe to any paid plan during or after the trial, the trial ends and your new plan takes effect immediately.
## Upgrading and Downgrading
You can change your plan at any time from [Settings > Plan](/s/most-recent-business/settings/plan).
**Upgrading.** When you upgrade to a higher plan, the change takes effect immediately. You're charged a prorated amount for the remainder of the current billing cycle — so if you upgrade halfway through the month, you only pay half the price difference.
**Downgrading.** When you downgrade, you keep access to your current plan's features through the end of your billing cycle. The lower plan takes effect when the next cycle begins. If the lower plan doesn't include features you were using (like Slack or CRM integrations), those integrations will be deactivated at that point.
## Cancellation
You can cancel your subscription at any time from [Settings > Plan](/s/most-recent-business/settings/plan). When you cancel:
- Your subscription remains active through the end of the current billing cycle. You won't be charged again.
- After the billing period ends, your business reverts to the Free plan.
- All of your data, content, and settings are preserved — nothing is deleted. You just lose access to paid features.
If you change your mind before the billing period ends, you can undo the cancellation and stay on your current plan.
## Payment Issues
If a payment fails (for example, due to an expired credit card), Quotient will continue to retry the charge for a short period. During this time, your access is unaffected — you'll see a banner prompting you to update your payment method, but nothing is locked.
If the payment remains unresolved after the retry period, your account's paid features will be restricted until the balance is settled. You can update your payment method at any time through [Settings > Plan](/s/most-recent-business/settings/plan) by clicking "Manage billing."
## Deleting a Business
If you delete a business from Quotient, any active subscription is cancelled immediately — not at the end of the billing cycle. This is permanent. If you think you might come back, consider cancelling your subscription instead, which preserves your data on the Free plan.
## Overage Rates
For reference, here are the current overage rates for paid plans. These apply only to usage beyond what's included in your plan:
Metric
Overage Rate
AI Credits
$26 per 1,000 credits
Emails Sent
$1.50 per 1,000 emails
Social Posts Published
$0.10 per post
Blog Posts Published
$0.10 per post
Overages are calculated automatically and added to your next invoice. You can estimate your monthly cost using the [pricing calculator](https://www.getquotient.ai/pricing).
-- End of: /plans-and-billing
-- Start of: /social
---
title: Social
description: Create and publish social media posts with Quotient
order: 4
---
Social media is a powerful channel for building your brand, engaging with your audience, and driving traffic to your website. Quotient helps you create compelling social media content tailored to each platform.
## Supported Platforms
Quotient currently supports creating and publishing posts to:
- **X (Twitter)** - Including support for threads
- **LinkedIn** - Professional networking and B2B content
- **Instagram** - Visual content and engagement
- **Facebook** - Pages and community engagement
- **TikTok** - Short-form video and photo carousels
## Creating Social Posts
Ask Quotient to help you [create social media posts](/s/most-recent-business/social) tailored to each platform. It understands the unique characteristics and best practices for each platform, including character limits, image requirements, and optimal posting strategies.
When you create a social post, you can:
- Write or edit the post content directly
- Add images and media
- Create multi-post threads (for X)
- Add a first comment (LinkedIn, Instagram, Facebook)
- Schedule posts for a specific date and time
- Track the status of your posts
## Publishing Your Posts
Once you've connected your social accounts in **Settings > Social Accounts**, Quotient can publish directly to each platform. Posts can be:
- **Published immediately** — click "Publish" to post right away
- **Scheduled** — set a date and time for automatic publishing
- **Unpublished** — remove a published post from the platform (X, LinkedIn, Facebook)
## Creating Posts with Quotient
Ask Quotient to help you create engaging social media content. It draws on its memory of your business, so everything it creates will be consistent with your brand's voice and messaging.
Here are some tips for getting the most out of Quotient when creating social posts:
- Provide context about your target audience and goals for each post
- Ask Quotient to create variations for different platforms
- Upload reference images or examples of posts you like
- Request specific hashtags or mentions to include
- Have Quotient create thread series for more in-depth topics
-- End of: /social
-- Start of: /analytics/identifying-users
---
title: Identifying Users
description:
Connect website activity to real people when they share their email address on
your site
order: 3
---
One of the most important jobs of Quotient's on-site tracking is to _identify_
visitors, so that you can attribute page views, sessions, and other events to
real people. Identifying visitors lets you measure, in a much more granular way,
which parts of your audience your marketing resonates with. Using
[flows](/docs/flow), it also lets you personalize each person's journey based on
their activity.
There are fundamentally two ways a visitor can reveal their identity to you:
1. **Implicitly**, by clicking a link that was sent specifically to them. If
someone receives an email and clicks a link to your site, Quotient knows who
they are, because the link carries a `qt_person_id` tag unique to that
person.
2. **Explicitly**, by entering their email address somewhere on your website.
This article focuses on the second way, because the first is handled for you.
Quotient's tracking tag detects identity from
[URL tags](/docs/analytics/tagging-and-attribution) automatically, with no extra
work on your part.
People identify themselves explicitly in a variety of ways, such as:
1. Booking a demo
2. Logging into your product
3. Signing up for a newsletter
Each of these works slightly differently. Below, we'll walk through how to
handle each one with Quotient.
The examples assume you've already
[installed the tracking tag](/docs/analytics/on-site-tracking) and have a
`client` from `QuotientClient.init()`. In a React app, get the same `client`
from the `useQuotient()` hook in `@quotientjs/react`.
## Announcing a Visitor's Identity
In most cases, including demo bookings and logins, you'll use
`client.audience.people.identify()` to announce a visitor's identity. Call it
any time someone enters their email address on your site.
`identify()` has only one required argument, `emailAddress`:
```typescript
await client.audience.people.identify({
emailAddress: "jane@example.com",
});
```
You can optionally include more information about the person, such as their
name, phone number, or the lists they should belong to. Here's how a demo
request form might call it after the form is submitted:
```javascript
async function handleDemoRequest(formData) {
await client.audience.people.identify({
emailAddress: formData.email,
firstName: formData.firstName,
lastName: formData.lastName,
mainPhoneNumber: formData.phone,
lists: ["people-who-booked-a-demo"],
});
}
```
`identify()` does four things:
1. If no person exists with that email address, it creates one.
2. If one does exist, it updates that person's record with the new data.
3. If a person was newly created, it records a `personCreated` event, which
feeds the _People Created_ metric. This event carries the visitor's
**attribution**, so you can break the metric down by campaign, by source, and
so on.
4. It stores the person's ID in the browser, whether they were newly created or
not, so that all future activity on that device is attributed to them.
For the full list of fields, see the
[Audience API reference](/docs/sdk/audience#identify-a-person).
## Email Sign-Up
Signing up for email is another way for a visitor to identify themselves, but it
carries special meaning in Quotient because it changes whether that person
receives your emails. For that reason, it has its own method in the Quotient
JavaScript SDK: `client.audience.people.subscribeToEmail()`.
Here's a newsletter sign-up form that uses it:
```html
```
This method does everything `identify()` does, with two extra effects:
1. It sets the person's email subscription status to _Subscribed_, so they start
receiving your email broadcasts. If someone has already unsubscribed, their
status is left alone. Signing up again never overrides an explicit
unsubscribe.
2. It records an `emailSubscribe` event, which powers the _Email Subscriptions_
metric, so you can measure how many new email subscribers your marketing
drove.
## Frequently Asked Questions
**Q: Should this code run in the browser or on the server?**
A: If possible, in the _browser_, because Quotient's tracking tag needs to store
the person's identity there. If you call `identify()` from your server, it will
still create or update the person, but it can't save their identity in the
browser, so their future activity won't be attributed to them. If your
conversion must be recorded on the server, see
[Server-Side Conversions](/docs/analytics/custom-events/server-side-conversions).
**Q: What if the visitor clears their cookies?**
A: Their identity is erased from that browser, and any future activity there
will no longer be attributed to them until they identify themselves again. This
is intentional and respects their privacy.
**Q: Is it okay to call `identify()` over and over again?**
A: Yes. Calling `identify()` again for the same person just updates their
record, so it's safe to call as often as you need. For example, you might call
it every time your website's login provider loads, since you may not be able to
tell a first-time login apart from a returning user.
## Next Steps
-- End of: /analytics/identifying-users
-- Start of: /analytics/index
---
title: Analytics
description: Measure how your marketing performs across every channel
order: 9
---
Quotient Analytics lets you analyze the performance of your marketing across
channels, see a full view of each customer's journey, and feed what you learn
back into your content strategy.
## Data Sources
Quotient collects data from four main sources:
1. **Email:** Quotient automatically tracks core engagement metrics for every
email it sends, from both **broadcasts** and automated **flows**. This
includes open rate, click-through rate, delivery rate, and more.
2. **Social Media:** Quotient syncs performance metrics such as likes, comments,
impressions, and reactions from social platforms like LinkedIn, X, Instagram,
and TikTok.
3. **Website:** Once you've installed the Quotient
[on-site tracking tag](/docs/analytics/on-site-tracking), Quotient
automatically tracks key activity on your website, like page views and
sessions. With some extra setup, Quotient can also track any other
[conversion events](/docs/analytics/custom-events) that matter to your
business.
4. **Audience:** Engagement with emails, social posts, and your website can be
attributed to individual members of your audience, painting a full picture of
the marketing each person and company has interacted with.
Combining these data sources lets Quotient answer sophisticated questions about
your entire marketing funnel, such as:
- How many new leads did this campaign generate?
- How many people from this company are opening my emails?
- How many conversions did our welcome series flow generate?
- Which channel sends more traffic to my site: email, social, or ads?
## Core Concepts
To understand how Quotient answers these questions, it helps to first understand
a few key terms.
### Events
An event is a single action a person performs, such as viewing a page, opening
an email, signing up for a newsletter, or booking a demo. Quotient records
events in two ways. Events that happen on your website are recorded by the
tracking tag. Events that happen elsewhere, like opening an email, are recorded
by Quotient automatically.
### Identity
Every event is tied to the person who performed it, and that person may be
_identified_ or _unidentified_. If someone opens an email, they are identified:
Quotient sent them the email, so it knows exactly who they are. If someone signs
up for your newsletter, they become identified, because now you know their email
address. But much of your website traffic comes from _unidentified_ people,
anonymous visitors whose identity you don't know yet.
[Identifying Users](/docs/analytics/identifying-users) explains how people
become identified.
### Attribution
Attribution is how Quotient gives credit to your marketing content and campaigns
for website traffic, leads, and ultimately conversions. Quotient keeps track of
which marketing each person saw before they took a key action on your site.
[Tagging and Attribution](/docs/analytics/tagging-and-attribution) covers this
in detail.
### Reports
A report answers a question about your data in Quotient. Reports draw on all of
the data sources above (email, social, website, and audience) to answer
questions about marketing performance. Every report is built from two main
ingredients: _metrics_ and _dimensions_.
### Metrics
A metric is a quantity you want to measure, such as Total Page Views, Total
Sessions, Total Emails Opened, Email Click-Through Rate, or Total Social
Impressions. Many metrics, though not all, are counts of events. Total Page
Views, for example, counts the events whose type is "page view."
### Dimensions
A dimension is how you break down a metric. You can break down a metric by time,
by campaign, by channel, and by many other variables. Dimensions are where
attribution and identity come into play. Because Quotient knows who performed
each event, you can break down key metrics not only by individual person, but
also by what people have in common: the country they're in, the company they
work for, or any custom property from your CRM.
## Asking Quotient About Performance
The same data feeds Quotient's own reasoning. Ask Quotient how a campaign
performed, what to double down on, or why one newsletter outperformed another,
and it answers from what it has measured for your audience.
## In This Section
-- End of: /analytics/index
-- Start of: /analytics/tagging-and-attribution
---
title: Tagging and Attribution
description:
How Quotient tags your links so website activity can be traced back to the
marketing that drove it
order: 1
---
When Quotient publishes content, such as social posts and email broadcasts, it
automatically appends **URL parameters** to every link. Quotient's
[tracking tag](/docs/analytics/on-site-tracking) then detects these parameters
and records them when it tracks activity on your website, such as sessions and
page views.
This process, often called "URL tagging," makes it possible to connect activity
on your website to the marketing content that led each person there.
For example, suppose someone sees a LinkedIn post published by Quotient, clicks
a link in the post, and lands on your website. URL tagging lets Quotient give
credit to that LinkedIn post for their page views. If the person keeps browsing
and eventually converts (whatever that means for your business), Quotient can go
one step further and attribute the conversion to the LinkedIn post, too.
URL tagging makes this possible by providing a record of which piece of content
_led_ the person to your website. There's nothing to set up. The links in your
drafts stay clean, and the tags are added when the content actually goes out:
each social post as it's published, and each email as it's sent, so every
recipient's copy carries its own tags.
## What a Tagged Link Looks Like
Suppose your newsletter links to `https://www.yourwebsite.com/pricing`. When
Quotient sends the email, it replaces that link with something like this (line
breaks added for readability):
```
https://www.yourwebsite.com/pricing
?utm_source=qt_email_broadcast
&utm_medium=email
&utm_campaign=product_launch_vff1xea7
&utm_content=june_newsletter_abcd1234
&qt_business_id=...
&qt_src_content_type=email_broadcast
&qt_src_content_id=...
&qt_campaign_id=...
&qt_person_id=...
&qt_email_id=...
```
The visitor still lands on your pricing page exactly as before. The extra
parameters don't change what the page does, but now the link itself records
where the visitor came from.
## URL Tag Glossary
Quotient tags every link with two sets of tags:
- **UTM tags** (short for Urchin Tracking Module) are an open standard that
marketing analytics tools have used for over two decades.
- **Quotient native tags** capture extra detail that UTM tags alone can't. They
identify the specific records in Quotient (the campaign, the email, the
person) behind each click, which lets Quotient paint a much more detailed
picture of each person's journey.
| Tag | Type | Definition |
| --------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| `utm_source` | UTM | Where the traffic came from. See [Source and Medium](#source-and-medium) for the values Quotient uses |
| `utm_medium` | UTM | The broader channel the source belongs to: `email` or `social` |
| `utm_campaign` | UTM | The campaign the content belongs to, as a human-readable name generated by Quotient. Left off when the content isn't part of a campaign |
| `utm_content` | UTM | The specific piece of content (email broadcast, flow, or social post) the link was in, as a human-readable name generated by Quotient |
| `qt_business_id` | Quotient | The ID of your business in Quotient |
| `qt_src_content_type` | Quotient | The type of content the link was in: `email_broadcast`, `flow`, or `social_post` |
| `qt_src_content_id` | Quotient | The ID of that piece of content in Quotient |
| `qt_campaign_id` | Quotient | The ID of the campaign the content belongs to. Left off when the content isn't part of a campaign |
| `qt_person_id` | Quotient | The ID of the person the email was sent to. Only present on links in emails |
| `qt_email_id` | Quotient | The ID of the individual email message sent to that person. Only present on links in emails |
A tag is either present with a value or left off entirely. Social posts never
carry `qt_person_id` or `qt_email_id`, because a post isn't sent to one specific
person.
### Source and Medium
Quotient sets `utm_source` and `utm_medium` automatically based on the kind of
content being published:
| Content type | `utm_source` | `utm_medium` |
| --------------- | ------------------------------------------------------------------------- | ------------ |
| Email broadcast | `qt_email_broadcast` | `email` |
| Flow email | `qt_flow` | `email` |
| Social post | the platform: `linkedin`, `twitter`, `instagram`, `facebook`, or `tiktok` | `social` |
### Readable Campaign and Content Names
The `utm_campaign` and `utm_content` values identify _which_ campaign and
_which_ piece of content a click came from. Quotient builds them from the
record's name plus a short unique suffix, so they stay readable:
- A campaign named "Product Launch" becomes `product_launch_vff1xea7`
- An email broadcast named "June Newsletter" becomes `june_newsletter_abcd1234`
These names are set when the campaign or content is created, and **they don't
change if you rename it later**. That's deliberate. If renaming a campaign
changed its tag, links already sitting in sent emails would report the old name
while new links reported the new one, and your reporting for that campaign would
split in two.
## UTM and GA4 Compatibility
Because UTM is an open standard, links published by Quotient are automatically
compatible with other marketing tools, including Google Analytics 4. Any GA4
report that breaks traffic down by `utm_campaign`, `utm_medium`, or `utm_source`
works with Quotient-published links, with no setup on your part.
Quotient also keeps every UTM tag consistent and legible, so you don't have to
worry about inconsistent casing or spacing, which often causes problems in
hand-built UTM links.
If you paste a link that already carries UTM parameters, Quotient replaces the
ones it manages with its own values so your reporting stays consistent.
Everything else about the link is preserved: other query parameters, `#section`
anchors, and the destination itself are never touched.
## Sessions and Attribution
When someone clicks through to your site, Quotient's tracking tag reads these
tags off the URL. That data (the content ID, content type, campaign ID, and so
on) is the visitor's **attribution**. It tells Quotient exactly which piece of
content the person most recently clicked and which campaign it was part of.
Attribution lasts for the duration of a **session**. A session starts when the
person first visits your website and ends after 30 minutes without any activity.
Every page view and event in that session is credited to the content that
brought them there.
## Identification
URL tags can also reveal the **identity** of the visitor. When someone clicks a
link in an email sent by Quotient, the `qt_person_id` tag tells Quotient exactly
who they are, because Quotient knows who it sent the email to.
Unlike attribution, which resets when the session expires, identity is kept
_indefinitely_. All future activity in that browser is attributed to that person
until they clear their browser's cookies and site data.
Tagged links aren't the only way to learn who someone is. A person can also
identify themselves _explicitly_ by entering their email address on your
website: signing up for a newsletter, registering for a webinar, booking a demo,
or logging into your app. You can learn how to capture these identities with
Quotient's JavaScript library in
[Identifying Users](/docs/analytics/identifying-users).
## How Clicks Are Counted
Email and social links both carry the same tags, but Quotient counts clicks on
them differently.
### Email
Quotient tracks every email from the moment it's sent, through delivery and
opens, without any links involved. Clicks are where URL tagging comes in, and
email handles them specially: links pass through Quotient on the way to their
destination. When a recipient clicks, the link briefly touches Quotient's
servers, the click is recorded, and the recipient is immediately forwarded to
the page they asked for.
Because Quotient itself records the click, **email clicks are counted no matter
where the link points**. A link to a YouTube video, a partner's website, or a
PDF has no tracking of its own, but the click is still recorded and attributed
to the exact campaign, email, and recipient.
The destination URL still carries the full set of tags, so when the visitor
lands on your own site, the visit is attributed there too, in both Google
Analytics and Quotient.
### Social
Social posts don't pass through Quotient. The tags are added directly to the
links in the post. Social platforms report clicks through their own analytics,
and when a click lands on your site, the tags tell your site's analytics where
the visit came from. Links in a LinkedIn post's first comment and in X thread
replies are tagged too.
A couple of platform quirks are worth knowing:
- **X** counts every link as exactly 23 characters regardless of its real
length, so tagging never eats into your character limit.
- **Instagram and TikTok** don't make links in captions clickable. Links only
work in your bio or in stickers. Quotient still tags these posts like any
other, so wherever a link can be clicked, attribution works.
## Frequently Asked Questions
**Q: Do you support more complex attribution models, like time decay?**
A: Currently Quotient uses **last-touch** attribution: credit goes to the most
recent piece of content the person clicked. In the future, we plan to add more
attribution models, such as first-touch, time decay, and U-shaped.
**Q: Are there any links Quotient doesn't tag?**
A: Yes, two kinds. The first is **links in your blog posts.** Your blog lives on
your own website, so a link from a blog post to your pricing page is an internal
link. The visitor is already on your site. Tagging internal links is a
well-known analytics mistake: UTM parameters signal the start of a new visit, so
Google Analytics would end the visitor's current session and credit your blog
instead of the real source. If someone arrives from a LinkedIn post and clicks
through your blog to your pricing page, the credit should stay with LinkedIn.
The second is **test sends and previews.** Links in editor previews and test
emails are left untagged, so your own test clicks never pollute your real
analytics.
**Q: What happens if someone clicks one link, starts a session, then clicks
another link halfway through that session?**
A: The second click _overwrites_ the existing attribution, but it doesn't start
a new session. That means any activity after the second click is credited to the
second piece of content, while activity before it stays credited to the first.
**Q: If someone identifies themselves halfway through a session, will Quotient
attribute their earlier, anonymous activity to them?**
A: Currently, no. Activity is only attributed to a person once they have been
identified. In the future, we plan to add _identity resolution_, which will
attribute previously anonymous activity to newly identified people.
## Next Steps
-- End of: /analytics/tagging-and-attribution
-- Start of: /audience/import-audience
---
title: Import Audience
description: Import contacts into Audience with a CSV file.
order: 1
---
If you already have contacts in another system, you can import them into
Audience with a CSV instead of adding people one by one. Start from the
[Upload CSV page](/s/most-recent-business/people/import-people/upload-csv), map
your columns to Quotient fields, and then run the import.
Quotient requires two fields for each contact:
1. `EMAIL` — a valid email address.
2. `EMAIL SUBSCRIPTION STATUS` — the contact's current marketing permission status.
Most other columns (like first name, company, job title, phone, city, and
country) are optional, but including them usually makes segmentation and
personalization more useful later.
## Email Subscription Status Values
Use one of the following values in the `EMAIL SUBSCRIPTION STATUS` column:
- `SUBSCRIBED` — The person is opted in and can receive marketing emails.
- `NOT_SUBSCRIBED` — The person has not opted in and should not receive
marketing emails.
- `UNSUBSCRIBED` — The person explicitly opted out and should not receive
marketing emails.
- `PENDING` — The person's subscription is waiting for confirmation.
These meanings match how unsubscribe and consent handling works in Quotient, so
it is important to use the exact values in your CSV.
## Validation Before Import
Before import starts, Quotient checks the first 100 records in your file. If it
finds invalid values for `EMAIL SUBSCRIPTION STATUS`, the upload is blocked so you
can fix the data first.
-- End of: /audience/import-audience
-- Start of: /audience/index
---
title: Audience
description: Build, organize, and understand your audience in Quotient
order: 7
---
Quotient's Audience section helps you understand and engage with your customers effectively. The platform enables you to:
- Track customer interactions and behaviors across channels
- Build detailed customer segments based on engagement patterns
- Personalize marketing campaigns using customer data
- Measure and analyze customer engagement over time
## Key Features
### Import Audience
Upload a CSV to quickly add or update contacts in bulk. [Start an
import](/s/most-recent-business/people/import-people/upload-csv), and review the
[import guide](/docs/audience/import-audience) for required fields and validation.
### People
View detailed information about individual customers, including their purchase history, email engagement, and preferences. [Explore your people](/s/most-recent-business/people) or learn more in our [people guide](/docs/audience/people).
### Segments
Create dynamic groups of customers based on shared characteristics or behaviors. [View your segments](/s/most-recent-business/segments) to target your marketing campaigns and analyze customer patterns.
### Working with Quotient
Ask Quotient to help you understand your customers better and suggest targeted marketing strategies based on your audience data.
-- End of: /audience/index
-- Start of: /audience/location
---
title: Location
description: How Quotient determines where your customers are located
order: 4
---
Understanding where your customers are located is crucial for personalized marketing. Quotient uses multiple data sources to build an accurate picture of each customer's location.
## How We Determine Location
Quotient uses several sources to determine customer location, in order of priority:
### 1. Profile Location
When a customer makes a purchase on your Shopify store, we get their billing address. This is our most reliable source of location data since customers typically enter their real address for billing purposes. We also use saved default addresses from Shopify customer accounts.
For example, if Jane places an order and enters a billing address in Toronto, Ontario, Canada, we'll use this as her primary location. This helps ensure marketing emails she receives are relevant to her region.
### 2. Company Location
If a person is associated with a company in your CRM and we don't have their direct location, we'll infer their location from the company's address. This is useful for B2B scenarios where individual contact addresses may not be available.
For instance, if Bob works at TechStart Inc which is headquartered in Austin, Texas, and we don't have Bob's personal address, we'll use Austin as his location.
### 3. Analytics Events
As a last resort, we use location data from analytics events (like page views or clicks) captured during website visits or interactions with your marketing campaigns. While less precise than profile or company addresses, this helps us understand where visitors are browsing from before they provide any address information.
## How We Choose Between Sources
We follow a strict priority order to always use the most reliable location data available:
1. Profile location from orders or saved addresses (highest priority)
2. Company location inferred from associated company
3. Analytics event location (lowest priority)
This means that:
- If a customer has a known address, we'll always use that
- If they're associated with a company, we'll use the company's location
- Only if we have neither will we fall back to their analytics event location
As customers interact more with your store - from browsing to creating an account to making purchases - our understanding of their location becomes increasingly accurate.
## Viewing Location Source
On the person detail page, you'll see a small label next to the location indicating where the data came from: **Profile**, **Company**, or **Analytics**. Hover over the label to see more details about the source.
## Why Location Matters
Knowing where your customers are helps you:
- Send emails at the right time for their timezone
- Create location-specific campaigns (like "Free Shipping to California")
- Personalize content based on regional preferences
- Comply with regional marketing regulations
For example, you might want to:
- Send a special promotion just to customers in New York
- Ensure customers in Australia receive emails during their daytime
- Notify West Coast customers about a pop-up shop in Los Angeles
-- End of: /audience/location
-- Start of: /audience/people
---
title: People
description: A deep dive into customer profiles in Quotient
order: 2
---
A customer profile in Quotient is a comprehensive record of an individual customer's interactions with your business. Each profile helps you understand who your customers are and how they engage with your brand.
## What's in a Profile?
Every customer profile includes:
### 1. Basic Information
- Email address
- Name (if provided)
- Location and timezone
- Sign-up date
### 2. Shopping Activity
- Purchase history
- Total spend
- Average order value
- Cart activity
- Product browsing history
### 3. Email Engagement
- Email subscription status
- Open and click rates
- Email preferences
- Campaign responses
### 4. Custom Properties
- Tags
- Custom attributes
- Segment memberships
- Notes and annotations
### 5. Lead Score
- `leadScore` — an integer you assign to indicate how qualified or engaged a
person is. Higher values typically represent more qualified leads. Defaults to
`0` and can be set or updated via the API.
## Viewing People
To access customer profiles:
1. Navigate to the **[People](/s/most-recent-business/people)** page in your dashboard
2. Use the search bar to find specific customers
3. Click on any profile to view detailed information
## Working with Profiles
You can:
- Add notes to profiles
- Update custom properties
- View detailed engagement timelines
- Export profile data
- Create segments based on profile attributes
Ask Quotient to analyze profiles and identify patterns in customer behavior. Try asking it questions about specific profiles or customer groups.
## Setting Lead Score via the API
You can set or update a person's `leadScore` when creating or updating them via
`POST /api/v0/audience/people`:
```typescript
await client.audience.people.upsert({
emailAddress: "jane@example.com",
leadScore: 85,
});
```
`leadScore` is an integer (default `0`). Pass any non-negative integer to
reflect how qualified or engaged the person is. You can update it at any time
by upserting the person with a new value.
-- End of: /audience/people
-- Start of: /audience/segments
---
title: Segments
description: Creating and managing customer segments in Quotient
order: 3
---
Segments in Quotient let you group customers based on shared characteristics or behaviors. They provide a powerful foundation for targeted marketing, personalization, and customer flow management.
## Understanding Segments
A segment is a group of customers who match specific criteria you define. Segments update dynamically - as customers' data changes, they'll automatically move in and out of segments based on whether they meet the criteria.
Segments are particularly valuable for:
- Sending targeted emails
- Creating personalized customer flows
- Analyzing customer behavior patterns
- Prioritizing sales and support resources
## Creating Segments
Quotient offers two different approaches to create segments, letting you choose the method that works best for your needs:
1. **Visual Editor** - A drag-and-drop interface for creating segments with precise control
2. **Chat** - Ask Quotient to build segments from natural language descriptions
You can freely choose between these methods depending on your preferences, the complexity of your segment, and your comfort level with technical details. Both approaches create the same type of segments with identical capabilities.
### 1. Segment Editor
Navigate to **[Segments](/s/most-recent-business/segments)** to use our visual editor. The editor lets you combine multiple filters with logical operators to define your target audience.
#### Available Filter Types
##### Person Filters
- **Properties**: Filter based on custom properties you've defined (text fields, numbers, dates, etc.)
- **Email Subscription**: Target based on subscription status (subscribed, pending, unsubscribed)
- **Location**: Filter by country, region, city using standard codes
- **Timezone**: Filter by IANA timezone identifiers
##### Analytics Filters
- **Events**: Filter based on actions like page views, add to cart, email opens
- **Event Frequency**: Target based on number of occurrences (exactly, greater than, less than, between)
- **Time Periods**: Filter events within specific timeframes (hours, days, weeks)
##### Company Filters
- **Company Name**: Target customers from specific companies
- **Company Location**: Filter by company's geographical location
- **Company Industry**: Segment by industry categories
- **Company Revenue**: Filter by company revenue ranges with currency options
- **Company Size**: Segment by employee count (enterprise, SMB, startup)
##### Deal Filters
- **Deal Amount**: Filter based on deal values (high, mid, low value deals)
- **Deal Status**: Target based on deal stages (in progress, won, lost, early stage)
#### Logical Operators
Combine filters with:
- **AND**: Customers must match all conditions
- **OR**: Customers must match at least one condition
- **NOT**: Exclude customers who match specific conditions
### 2. Building Segments with Quotient
You can also ask Quotient to build segments through natural conversation. Simply describe the customers you want to target, and it will create the appropriate segment.
#### Example Prompts
**Basic Segments:**
- "Create a segment of customers with a lead score over 100"
- "Show me customers who haven't opened emails in 30 days"
- "Find customers in the Pacific timezone who bought recently"
**Company-Based Segments:**
- "Create a segment of customers from tech companies in California"
- "Find people from healthcare companies with more than 100 employees"
- "Segment customers from companies with over $10M in revenue"
**Deal-Based Segments:**
- "Create a segment of people with deals in the proposal stage"
- "Find customers with high-value deals over $50,000"
- "Segment people with won or lost deals in the last quarter"
**Complex Segments:**
- "Create a segment of customers from financial companies who opened our last email and have active deals"
- "Find customers in Canada with a lead score over 500 who viewed our product page at least 3 times"
- "Create a segment of enterprise customers who haven't engaged in 90 days and have active deals"
## Advanced Segmentation Strategies
### Behavioral Segmentation
Target customers based on how they interact with your business:
- **Engagement Level**: Highly engaged vs. at risk of churn
- **Purchase Frequency**: Frequent buyers vs. one-time customers
- **Product Interest**: Based on page views, searches, or cart additions
- **Email Response**: Regular openers vs. non-responders
### Lifecycle Segmentation
Target based on customer flow stage:
- **New Subscribers**: Recent signups who haven't purchased
- **First-Time Buyers**: Converted from prospects to customers
- **Repeat Customers**: Made multiple purchases
- **VIP Customers**: High lifetime value, frequent purchasers
- **At-Risk**: Declining engagement or purchase frequency
- **Lapsed**: Haven't engaged in a defined timeframe
### B2B Segmentation
For business customers, leverage company and deal data:
- **Industry Vertical**: Target specific industries with relevant messaging
- **Company Size**: Different approaches for enterprise vs. SMB
- **Deal Stage**: Tailor content based on sales funnel position
- **Deal Value**: Prioritize high-value prospects
- **Decision Maker Role**: Target based on position in company
## Using Segments
Once created, you can use segments in multiple ways:
### Email Broadcast Targeting
- Select specific segments as the audience for your email broadcast
- Exclude segments from receiving certain campaigns
- Create more personalized messaging for different customer groups
- A/B test campaign effectiveness across different segments
### Customer Flow Personalization
- Start flows for specific segments
- Create conditional branches in flows based on segment membership
- Customize flow actions based on which segments a customer belongs to
## Best Practices
### Segment Design
1. **Start with clear objectives**: Define what you want to achieve before creating segments
2. **Keep segments focused**: Create specific segments for clear use cases rather than trying to cover too many criteria in one segment
3. **Use descriptive names**: Name segments clearly to communicate their purpose (e.g., "High-Value Tech Companies" is better than "Segment A")
4. **Add detailed descriptions**: Document segment criteria and intended use cases
### Segment Management
1. **Update regularly**: Review and update your segments periodically to ensure they remain relevant
2. **Archive unused segments**: Keep your workspace clean by archiving segments you no longer need
3. **Test before sending**: Always preview your segment size and composition before using it in campaigns
4. **Start small**: When using a new segment, test with a small campaign before scaling
5. **Track segment performance**: Monitor how different segments respond to your marketing
### Optimization Strategies
1. **Refine based on performance**: Adjust segment criteria based on campaign results
2. **Progressive profiling**: Build more detailed segments over time as you gather more customer data
3. **Segment hierarchies**: Create broader segments for general campaigns and more specific sub-segments for targeted messaging
4. **Combine behavioral and demographic data**: The most effective segments often use both types of information
## Troubleshooting
### Common Issues
- **Empty segments**: If a segment contains no users, check for overly restrictive criteria or data issues
- **Oversized segments**: Very large segments may need more specific criteria for effective targeting
- **Slow-updating segments**: Some segment criteria may take time to evaluate for large customer bases
- **Conflicting criteria**: Using contradictory conditions may create unexpected results
### Getting Help
Ask Quotient to help you:
- Diagnose issues with existing segments
- Optimize segment criteria for better targeting
- Suggest new segmentation strategies based on your business goals
- Convert natural language descriptions into technical segment definitions
-- End of: /audience/segments
-- Start of: /email/email-status
---
title: Email Status
description: What Email Status means inside of Quotient
---
When you send email with Quotient, each email will have a status that tracks
it's delivery and engagement. Please see the table below for
an overview of each status and its description:
Status
Description
`QUEUED`
Quotient has queued the email to be sent
`SENT`
Quotient is attempting to deliver the email to the recipient
`ERROR`
An error prevented Quotient from sending the email
`DELIVERED`
Quotient delivered the email to the recipient
`DELIVERY_DELAYED`
Quotient could not deliver the email due to a temporary issue; Quotient
will continue attempting delivery
`BOUNCED`
The recipient's mailbox permanently rejected the email
`OPENED`
Quotient delivered the email and the recipient has opened it
`CLICKED`
Quotient delivered the email, the recipient has opened it, and clicked
on a link inside of it
`COMPLAINED`
Quotient delivered the email and the recipient marked it as spam
Please note that the status of an email reflects the most recent event to occur
to it, so if a recipient opens an email, clicks a link inside of it, and then
marks the email as spam, Quotient will mark this email as `COMPLAINED`.
-- End of: /email/email-status
-- Start of: /email/index
---
title: Email
description: Send email broadcasts and automated emails with Quotient
order: 5
---
Email is one of the most important tools in your marketing toolkit. Email marketing remains one of the most effective ways to nurture leads, build relationships with customers, and drive sales for your business.
Quotient lets you craft, send, and measure emails — and you can ask Quotient to handle any part of the process for you.
## Core Concepts
**Broadcasts**
[Broadcasts](/s/most-recent-business/email-broadcasts) are a one-time blast email to a portion of your audience. A broadcast is made up of...
- **Content:** HTML content that recipients will see in their inbox. You can edit the content of the email directly in the email editor, or you can ask Quotient to make updates on your behalf.
- **Metadata**: Additional data about the email including the subject line, preview text, and from address. Setting metadata correctly helps improve the performance and deliverability of emails.
- **Send Time:** The time at which the email will begin sending to recipients. We say "begin sending" because not all of the emails will be sent immediately at the send time. To improve deliverability, we send the emails in batches over the course of several minutes.
Email broadcasts follow a three-stage lifecycle: **Draft** → **Scheduled** → **Launched**. You can either schedule a broadcast for a specific time in the future or launch it immediately. Once the broadcast is launched and emails start sending, it moves to the "Launched" status. Once launched, broadcasts can no longer be modified - this is different from blogs, which can be re-published after going live. Once an email has been sent, you can't change it.
**Audience**
“Audience” refers to the people you've designated to receive an email broadcast. The audience can be made up of both **lists** and **segments**. You can learn more about the difference in the article on Building Your Audience.
You can include multiple lists and/or segments in the audience for your broadcast. If a person appears in multiple, Quotient will deduplicate and ensure that they only receive the email once.
**Analytics**
If you're using Quotient to send email, we will automatically track the performance of your broadcasts, including:
1. **Delivery Rate:** Of the emails sent, how many were successfully delivered.
2. **Open Rate:** Of the emails delivered, how many were opened by the recipient.
3. **Click Rate:** Of the emails opened, how many people clicked on a link leading to your website.
**Templates**
[Templates](/s/most-recent-business/email-template) are reusable blueprints of email content. It's important to understand that templates are not directly sent out - they must either be cloned into a broadcast or used as part of a flow. There are two different ways you can use templates:
1. **Starting Point for Broadcasts:** It's common to clone templates as a starting point for email broadcasts. This ensures that all email broadcasts maintain a consistent structure and look. For example, you might have a template for your weekly newsletter, and each week you would clone it and replace the content for that week.
2. **In Automated Flows:** Templates can also be used inside of **flows**. In Quotient, flows are automated processes that can send email to customers based on pre-defined schedules or triggers. A common example would be sending new users an automated welcome series after they sign up for your product. To learn more about flows, check out the [Flows](/docs/flow) article.
**Components**
[Components](/s/most-recent-business/email-components) are reusable blocks of email content that can be used in both broadcasts and templates and stay automatically up-to-date. The most common examples of components are **headers and footers**.
Typically you want your headers and footers to stay consistent across all your emails, and if you change them, you want them to update automatically in all the templates/broadcasts where they're used.
**Email Domains**
[Email domains](/s/most-recent-business/email-settings) are the domains that your emails are sent from (e.g., `updates@yourcompany.com`). Using a custom email domain is crucial for deliverability and brand consistency. It helps ensure your emails reach the inbox rather than being marked as spam.
Quotient helps you set up and verify custom email domains with proper DNS configuration. You can learn more about setting up custom DNS in our [Custom DNS guide](/docs/email/dns).
## Creating Emails with Quotient
Ask Quotient to help you create any of the above — broadcasts, templates, components, and finding the right audience for each email.
Quotient draws on its memory of your business, so the content it creates will be consistent with your brand's voice and messaging strategy.
Here are some tips for getting the most out of Quotient when working with email:
- When setting up your Quotient account, ask Quotient to create a standard header, footer, and "base template", and ask it to remember to always use those as a starting point. This helps keep your emails consistent and on-brand, and ensures that Quotient doesn't have to reinvent the wheel with each new broadcast.
- Formatting emails is notoriously difficult due to the esoteric requirements of legacy email clients. We recommend asking Quotient to take the first stab at creating the content. From there you can use the editor to tweak copy and styles. This is often easier than creating the formatting yourself.
- You can upload screenshots of emails from other brands to the chat panel and ask Quotient to copy them or use them as inspiration.
- Emails should always have CTAs that lead to pages on your website where readers can learn more and hopefully enter your conversion funnel. To set CTAs up properly, Quotient needs to understand your website structure. Ask Quotient to crawl your website and save a memory describing it, which it can then use to construct links.
## Inbound vs. Outbound Email
It's important to note that Quotient is used for **inbound email marketing**, not **outbound email marketing.** Inbound marketing targets people who have _already_ shown interest in your product - like signing up for a demo or newsletter - whereas outbound marketing, also known as "cold email", proactively reaches out to people regardless of their expressed interest.
There are a few key differences between inbound and outbound email marketing:
Inbound
Outbound
Typically comes from a company email address, e.g.
updates@mail.company.com
Usually comes from an individual salesperson, e.g. max@getquotient.ai
Emails are not meant to be replied to and may come from a "noreply"
address
Emails are meant to be replied to - the goal is to start a conversation
with the salesperson
Emails may be somewhat personalized, but typically are sent as
"broadcasts", i.e. sending the same email to many people
Emails are often highly personalized and tailored to each individual
prospect
Emails typically contain rich formatting, images, and CTAs
Emails are usually written in plain text
If you’re looking for an outbound email marketing platform, here are a few we recommend:
- [SalesLoft](https://www.salesloft.com/)
- [Apollo](https://www.apollo.io/)
- [Outreach](https://www.outreach.io/)
- [Unify](https://www.unifygtm.com/)
## Next Up
-- End of: /email/index
-- Start of: /email/suppression
---
title: Suppression & Bounce
description: Understanding email suppression and bounce handling.
---
Quotient uses a combination of user-submitted manual suppression and bounce detection to manage email suppression lists.
When an email address is added to a business's suppression list, Quotient will
automatically suppress the email address.
## Manual Suppression
A Quotient user can manually suppress an email address via the `manuallySuppressed` field when uploading an email list. Please see
the [building-email-list](/docs/email/building-email-list#3.-manual-upload-and-quick-add) guide for more information.
## Automatic Suppression
Quotient allows users to upload all syntatically valid email addresses, but
will suppress email to email addreses with invalid top-level domains (TLDs)
as well as to email addresses that end in IANA special-use domains.
**For more information, see the resources below:**
- [IANA List of Top-Level Domains](https://data.iana.org/TLD/tlds-alpha-by-domain.txt)
- [IANA Special-Use Domain Names](https://www.iana.org/assignments/special-use-domain-names/special-use-domain-names.xhtml)
## Bounces
An email "bounces" when it is not delivered to the inbox of the recipient, or
if the email is rejected by the recipient's email provider. If your Quotient
account has a large number of bounces, this can negatively impact deliverability.
In order improve deliverability, Quotient monitors and detects email bounces for all emails sent via Quotient.
### Bounce Types and Detection
Quotient monitors and detects email bounces for all emails sent via Quotient.
There are two types of bounces and a number of subtypes:
- **Hard Bounce:** A hard bounce is a permanent failure to deliver an email.
- **General**: The email provider sent a hard bounce message
- **Domain Does Not Exist**: The email address domain does not exist
- **User Does Not Exist**: The email address user does not exist
- **Blocked**: Your domain is blocked by the recipient's email provider
- **Soft Bounce:** A soft bounce is a temporary failure to deliver an email.
- **General**: The email provider sent a general bounce message, in which case the email
address may not bounce again in the future
- **Mailbox Full**: The recipient's mailbox is full
- **Message Length & Size**: The message is too long or to large
- **Rate Limited**: The provider is receiving too many emails within a given time period and is temporarily rejecting new ones
- **Content**: The content of the message is rejected by the recipient's email provider for spam reasons
- **Sender Reputation**: The provider determines your domain has poor sender reputation
- **DNS Issues**: Temporary DNS failures or routing problems
Email addresses that receive **Hard Bounces** are automatically suppressed and will not receive any emails. These email addresses are added to Quotient's global suppression list, which is used for all emails across all businesses. This ensures that emails are not sent to email addresses that are known to bounce.
Email addresses that receive **Soft Bounces** are not suppressed until they
exceed our soft bounce occurence threshold of 7 for a given business. At that point, they are added to the business's suppression list.
### Suppression Lists
Quotient maintains a global suppression list for hard bounces. This means that once an email address is suppressed due to bouncing, it will remain suppressed for all emails across all businesses, ensuring that emails are not sent to email addresses that are known to bounce.
Quotient also maintains a business-specific suppression list for soft bounces
and manually suppressed emails. This means that once an email address is suppressed due to bouncing or manual suppression, it will remain suppressed for the duration of the business's Quotient account.
-- End of: /email/suppression
-- Start of: /email/unsubscribe
---
title: Unsubscribe
description: How email unsubscribes work and how to customize the unsubscribe page.
---
It is crucial to provide email recipients with the ability to unsubscribe from
your email broadcasts in order to maintain a good sender reputation.
Giving recipients the ability to unsubscribe from your email broadcasts:
- reduces the likelihood that your emails are marked as spam
- improves deliverability for your email broadcasts
In Quotient, use the **Unsubscribe Link** component in your email footer to give
recipients the option to unsubscribe from your emails. Quotient also includes a
`List-Unsubscribe` header on outgoing emails, so many inbox providers can show a
native one-click unsubscribe button.
- **One-click unsubscribe (inbox provider button):** The inbox provider calls
Quotient's unsubscribe endpoint. The person is unsubscribed without needing to
load a confirmation page.
- **Footer link unsubscribe:** The person lands on your branded unsubscribe page
and confirms by clicking the unsubscribe button.
## What Happens When Someone Unsubscribes
Quotient immediately updates that person's email subscription status to `UNSUBSCRIBED`.
From that point forward, they are excluded from marketing sends, even if they
still appear in a list or segment.
## Subscription Statuses
State
Description
`SUBSCRIBED`
Opted in. Will receive marketing emails.
`NOT_SUBSCRIBED`
Has not opted in. Will not receive marketing emails.
`UNSUBSCRIBED`
Explicitly opted out. Will not receive marketing emails.
`PENDING`
Subscription pending confirmation.
## Customizing the Unsubscribe Page
You can customize the copy on your unsubscribe page in [Email
Settings](/s/most-recent-business/settings/email-settings):
- **Dark mode** — enables a dark unsubscribe page treatment
- **Show logo** — controls whether your brand logo appears on the page
- **Accent color** — sets the unsubscribe button color
- **Heading** — defaults to "Unsubscribe from [Brand Name]"
- **Subheading** — defaults to "You're currently subscribed to emails from
[Brand Name]."
- **Button text** — defaults to "Unsubscribe"
Quotient also provides a preview so you can check how the page looks before
saving changes.
-- End of: /email/unsubscribe
-- Start of: /integrations/index
---
title: Integrations
description: Connect Quotient to the other tools you use to run your marketing
order: 700
---
Quotient works best when it can see the rest of your marketing stack. Connect
your CRM and Quotient keeps your audience in sync with it. Connect your website
and your blog posts publish straight from Quotient. Connect Zoom and your
webinar registrations and attendance flow into your campaigns.
You can connect any of these tools from
[Settings → Integrations](/s/most-recent-business/settings/integrations). Each
guide below walks through setup and explains what gets synced.
Looking to connect Quotient to an AI app, or give Quotient access to another
tool through MCP? See [MCP](/docs/mcp).
-- End of: /integrations/index
-- Start of: /integrations/slack
---
title: Slack
description:
Connect Slack to receive notifications and interact with Quotient
directly from your workspace
order: 5
---
Quotient's Slack integration lets you receive notifications and interact with
Quotient directly from your Slack workspace. There are two main capabilities:
1. **Notifications** — Receive updates about your marketing activities directly
in Slack
2. **Talking to Quotient** — Chat with Quotient without leaving
Slack
## Getting Started
To enable the Slack integration, navigate to **[Integrations > Slack](/s/most-recent-business/integrations)** in
Quotient and click **Connect to Slack**. You'll be prompted to authorize
Quotient to access your Slack workspace. Once connected, you can start receiving
notifications and chatting with Quotient immediately.
## Notifications
Quotient can send you notifications about important events—like when it
completes a task or needs your input—directly to Slack. These notifications
arrive as direct messages from the Quotient bot, keeping your channels
clutter-free while ensuring you never miss an important update.
### Configuring Notification Preferences
You can customize which notifications you receive in Slack from your
notification preferences. Navigate to **[Settings > Notifications](/s/most-recent-business/preferences?tab=notifications)** to control
exactly what types of updates Quotient sends you.
For each notification type, you can choose:
- **Immediate** — Receive the notification in Slack right away
- **None** — Don't send this notification type to Slack (you may still receive
it via email)
## Talking to Quotient in Slack
You can interact with Quotient directly from any Slack channel or
direct message—just mention **@Quotient** and start chatting.
### How It Works
When you mention @Quotient in Slack, here's what happens:
1. **Quotient processes your request** — Your message is sent to Quotient, which
works on your request
2. **A thread is created in Quotient** — The conversation becomes a thread in
Quotient that you can view anytime
3. **You get a response in Slack** — Once processing is complete, Quotient
replies in the same Slack thread with a summary of what was accomplished
The entire conversation—including all the work Quotient did—is visible in
the Quotient app. Just click the "View in Quotient" link in the response to see the full
thread.

### Using Conversation Context
When you mention @Quotient mid-thread, it can see the full conversation history
leading up to your message. This means you can discuss ideas with colleagues
first, then bring Quotient in to execute.
For example:
Marc
I have an idea for a new campaign. We should target our enterprise
customers with content about our new analytics features.
Alex
Love it. Let's do a blog post and some LinkedIn posts from our company
page.
Marc
Perfect.{" "}
@Quotient{" "}
make it happen!
Quotient{" "}
APP
Done! I've created a campaign called "Enterprise Analytics Launch" with:
Blog post: "5 Ways Advanced Analytics Transforms Enterprise Marketing"
Because Quotient can see the entire conversation, it understands exactly what
you're asking for without you having to repeat the context.
### Continuing the Conversation
If you need to make changes or ask follow-up questions, just reply in the same
Slack thread and mention @Quotient again. Your follow-up will be added to the
same Quotient thread, preserving the full context of your conversation.
### File Attachments
You can attach files to your messages when chatting with Quotient in Slack. Any
file type that Quotient supports—such as images, PDFs, and documents—will be
processed. Unsupported file types are simply ignored.
### Tips for Getting the Most Out of Slack
Here are a few tips to help you work effectively with Quotient in Slack:
- **Be specific in your requests.** The more context you provide, the better
Quotient can help. Instead of "create a campaign," try "create a campaign for
our product launch next month targeting enterprise customers."
- **Use threads for context.** When you mention @Quotient in an existing thread,
it can see the full conversation history. Use this to your advantage by
discussing ideas with your team first, then bringing Quotient in to execute.
- **One request at a time.** Like most AI applications, Quotient processes one
message at a time. If you send a follow-up while Quotient is still working on
your previous request, it may ask you to wait until it's finished.
- **Check the full thread in Quotient.** The response you see in Slack is a
summary. For the full details of what Quotient did—including any drafts it
created—click through to view the thread in Quotient.
## Troubleshooting
### Quotient isn't responding to my @mention
Make sure Quotient has been added to the channel where you're trying to mention
it. In private channels, you may need to invite Quotient first using
`/invite @Quotient`.
### I'm not receiving notifications in Slack
Check your notification preferences in **[Settings > Notifications](/s/most-recent-business/preferences)** to ensure
Slack notifications are enabled for the notification types you want to receive.
Also verify that your Slack integration is still connected in **[Integrations >
Slack](/s/most-recent-business/integrations)**.
### My file attachment wasn't processed
Quotient only processes supported file types. If your file wasn't processed, it
may be an unsupported format. Try converting it to a common format like PDF or
PNG.
-- End of: /integrations/slack
-- Start of: /integrations/zoom
---
title: Zoom
description:
Connect Zoom to create meetings and webinars from Quotient, sync
registration and attendance, and run follow-up campaigns
order: 4
---
Quotient's Zoom integration lets you plan webinars and meetings as marketing
events, keep registration in sync with Zoom, pull attendance after the session
ends, and use that data in segments and Flows.
This page covers how to add the app, use it, and remove it.
## Prerequisites
- A Quotient workspace
- A Zoom account that can authorize apps (admin or owner is typical)
- For **Zoom Webinars** (registration pages, panelists, one-to-many broadcast): a
Zoom plan with the Webinar add-on. Without it, use **Meetings** instead
(workshops, roundtables, smaller interactive sessions)
## Adding the app
Install from Quotient. Marketplace users land on the [Zoom integration
page](/integrations/zoom) and continue into the product to connect.
### Step 1: Open Zoom in Integrations
1. Sign in to Quotient
2. Go to **[Settings → Integrations](/s/most-recent-business/settings/integrations)**
3. Find the **Zoom** card and click **Connect**
You can also open **[Zoom integration settings](/s/most-recent-business/settings/integrations/zoom)**
directly.
### Step 2: Authorize in Zoom
Quotient redirects you to Zoom's authorization page. Sign in if prompted, review
the permissions Quotient is requesting, and approve.
Quotient asks Zoom for permission to:
- Create and read meetings and webinars
- List existing meetings and webinars so you can link them
- Add and read webinar registrants
- Read past meeting and webinar participants
- Read the connected Zoom user (connection health and host exclusion)
OAuth access and refresh tokens are stored encrypted at rest (AES-256-CBC). They
are not stored in plaintext.
### Step 3: Confirm the connection
After you approve, Zoom sends you back to Quotient. On the Zoom integration
card you should see **Connected**.
If authorization fails, see [Troubleshooting](#troubleshooting).
## Using the app
All Zoom work in Quotient lives under **[Marketing
Events](/s/most-recent-business/marketing-events)**.
### Create a Zoom session
When you create a marketing event, you can:
- **Create a Meeting** — a standard Zoom meeting tied to the event. Use this for
workshops, roundtables, or smaller interactive sessions.
- **Create a Webinar** — Zoom's webinar format with registration, panelists, and
broadcast. Requires the Zoom Webinar add-on.
- **Connect an existing meeting** — link a meeting you already created in Zoom
to a Quotient event. Quotient lists meetings and webinars from the connected
account so you can pick one.
After you create or link a session, Quotient stores the Zoom event ID, schedule,
and join / registration URLs on the marketing event.
### Registration sync
- **Push to Zoom** — when someone registers for the event in Quotient, Quotient
can add them as a Zoom registrant.
- **Pull from Zoom** — registrations that came in through Zoom's registration
page are imported into Quotient (email, name, status).
- **Bidirectional sync** — keep both lists aligned. Zoom webhooks also notify
Quotient when a registration is created or cancelled.
Registrants are stored as People and event participants in Quotient so you can
email them and include them in Flows.
### Attendance tracking
After the session ends, Quotient pulls attendance from Zoom (join time, leave
time, duration) and updates participant status to **Attended** or **No Show**.
The host is excluded from lead / participant sync when Quotient can resolve the
host user.
You can then:
- Segment attendees vs no-shows for follow-up email
- Build audience filters from event participation (for example, “attended this
webinar”)
- Trigger [Flows](/docs/flow) on marketing-event status changes (registered,
attended, no-show)
- Report on attendance rate, no-show rate, and duration
## Removing the app
Remove the connection in **both** places if you want Zoom and Quotient fully
disconnected.
### In Quotient
1. Go to **[Zoom integration settings](/s/most-recent-business/settings/integrations/zoom)**
2. Open the options menu (⋯) on the Zoom card
3. Click **Delete Integration** and confirm
This deletes the Zoom connection for that workspace, including encrypted OAuth
tokens. Quotient can no longer create Zoom sessions, sync registrants, or pull
attendance for that account.
Marketing events, people, and historical attendance records already in Quotient
are not automatically deleted. Disconnecting stops new Zoom API access; it does
not wipe your event history. Remove those records separately in Quotient if you
need them gone.
To reconnect later, click **Connect** again and complete Zoom authorization.
### In Zoom
If you installed or authorized the app from Zoom as well:
1. Sign in to the [Zoom App Marketplace](https://marketplace.zoom.us/)
2. Click **Manage** → **Added Apps**, or search for **Quotient**
3. Open the app and click **Remove**
4. Confirm
After removal, Quotient cannot call Zoom APIs for that Zoom account until
someone reconnects. Existing Quotient event and contact data is unchanged unless
you delete it in Quotient.
## Troubleshooting
**Connect never finishes / you don't return to Quotient**
- Allow pop-ups for getquotient.ai and zoom.us
- Try a private browser window
- Confirm you approved the correct Zoom account
**Connected, then it drops**
Zoom invalidates tokens if the same Zoom account is connected from another
device, browser, or environment (for example production and staging). Disconnect
and reconnect, or use separate Zoom accounts per environment.
**Can't create a webinar**
The connected Zoom account needs the Webinar add-on. Create a **Meeting**
instead, or upgrade the Zoom plan.
**Registrants or attendance don't show up**
- Confirm the marketing event is linked to the right Zoom meeting or webinar ID
- Wait until the session has ended for attendance (past participants)
- Reconnect Zoom if the integration health check fails
**Need help?** Email [support@getquotient.ai](mailto:support@getquotient.ai) or
use [Support](/support).
-- End of: /integrations/zoom
-- Start of: /mcp/index
---
title: MCP
description: How Quotient works with the Model Context Protocol (MCP) — both connecting tools to Quotient and using Quotient from other AI apps.
order: 750
---
[MCP (Model Context Protocol)](https://modelcontextprotocol.io/) is an open standard that lets AI apps securely connect to other software. Think of it as a universal adapter: once a tool supports MCP, any AI app can plug into it.
Quotient works with MCP in **two directions**, and it's worth knowing which one you want before you dig in:
* **Connect tools _to_ Quotient.** Give Quotient access to outside tools — like GitHub, Notion, or Ahrefs — so it can use them while you chat. For example, Quotient can read your latest pull requests and draft a changelog. (In technical terms, Quotient acts as an MCP *client*.)
* **Use Quotient _from_ other AI apps and agents.** Connect Quotient to AI apps — like ChatGPT, Claude, Cursor, or Codex — so they can do work in your Quotient account on your behalf. For example, Claude Code can create a campaign or publish a social post for you. (In technical terms, Quotient acts as an MCP *server*.)
The simplest way to keep them straight: in the first case, **Quotient reaches out** to other tools; in the second, **other apps reach in** to Quotient.
## Pick Your Path
-- End of: /mcp/index
-- Start of: /sdk/analytics
---
title: Analytics
description: Track page views and custom events with the Quotient analytics API
order: 4
---
## Overview
Use the analytics API to connect activity on your site, such as viewing a page
or custom event that you define, to the marketing that brought each visitor
there.
The client SDK (`@quotientjs/client` or `@quotientjs/react`) runs in the
browser. It adds the visitor's session, attribution, and identity to each event.
The server SDK (`@quotientjs/server`) tracks backend events about a person you
already know.
| Endpoint | API Key | SDK | Method |
| --------------------- | ------- | ---------- | --------------------------------- |
| Track a browser event | public | Client SDK | `client.analytics.event(event)` |
| Track a server event | private | Server SDK | `quotient.analytics.event(event)` |
## Track a Client Event with @quotientjs/client
#### `client.analytics.event(event)`
> `POST /api/v0/analytics/web`
>
> **Auth:** public key · scope: `ANALYTICS_WRITE`
Every client event includes the current session ID, device ID, browser
fingerprint, page URL, and attribution. Attribution comes from the `utm_*` and
`qt_*` parameters on the visitor's incoming URL and lasts for the current
session. If a tagged link or `client.audience.people.upsert()` identifies the
visitor, the SDK includes their `personId` too. You only provide the event.
| `eventType` | Extra fields | Description |
| ------------ | ----------------------- | ---------------------------------------------------------------------------- |
| `"pageView"` | none | A page view. The SDK tracks these automatically by default |
| `"custom"` | `customEventId: string` | The ID of an event defined by your business, such as `"completedOnboarding"` |
```typescript
// Page view (usually automatic; see Auto-Tracking below)
await client.analytics.event({
eventType: "pageView",
});
// Custom event
await client.analytics.event({
eventType: "custom",
customEventId: "completedOnboarding",
});
```
**Returns:** `void`
Register each custom event in Quotient before sending it. Pass its immutable
event ID as `customEventId`; the API rejects IDs that have not been registered
for your business.
Pass `idempotencyKey` on any event to avoid recording it twice, such as when a
retry resends the same request. Quotient checks for a matching key from your
business for 24 hours; a duplicate within that window is dropped instead of
recorded again. This check depends on our caching layer being reachable; a
rare outage there can still let a duplicate through.
## Track a Server Event
#### `quotient.analytics.event(event)`
> `POST /api/v0/analytics/server`
>
> **Auth:** private key · scope: `ANALYTICS_WRITE`
Use a server event when an activity that matters to your marketing analytics
does not take place in a browser. These activities often happen in webhooks,
OAuth callbacks, scheduled jobs, or other backend code. For example, you might
track when a free trial expires, a customer upgrades their plan, or a user
completes onboarding.
The server API currently accepts custom events only. Each event must be about a
known person, so include their `personId`, the person's identifier in Quotient.
It must belong to an existing person in your business. Because the event does
not come from a browser, the SDK cannot add a browser session or its attribution
automatically. Pass the visitor's browser context yourself as `browserContext`
(see
[Server-Side Conversions](/docs/analytics/custom-events/server-side-conversions)),
or attribute the event to a campaign directly with `campaignId`.
| Field | Type | Required | Description |
| ---------------- | ---------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `eventType` | `"custom"` | Yes | Server events are always custom events today |
| `personId` | `string` | Yes | The Quotient identifier of the person this event is about |
| `customEventId` | `string` | Yes | A custom event ID already registered for your business |
| `campaignId` | `string` | No | Attributes the event to a specific campaign |
| `browserContext` | `BrowserContext` | No | What the browser SDK knew about the visitor when the conversion happened, read from the `qt_browser_context` cookie or `client.getBrowserContext()` |
| `idempotencyKey` | `string` | No | Prevents recording the same event twice, such as when a retry resends the same request. Quotient checks for a matching key from your business for 24 hours (a rare caching-layer outage can still let a duplicate through) |
```typescript
await quotient.analytics.event({
eventType: "custom",
personId: "person_abc123",
customEventId: "upgradedPlan",
});
```
**Returns:** `void`
## Read the Browser Context
#### `client.getBrowserContext()`
Returns what the browser SDK currently knows about the visitor: device, session,
person, referrer, and attribution. The SDK also writes the same object to the
`qt_browser_context` cookie on every tracked event, so a server on your own
domain can read it without any call from the page.
```typescript
const browserContext = client.getBrowserContext();
```
**Returns:** `BrowserContext`
Use it when a conversion completes on a server that the cookie cannot reach,
such as an API on another domain, and pass the object along in your request
body.
[Server-Side Conversions](/docs/analytics/custom-events/server-side-conversions)
walks through both paths and the shape of the object.
## Auto-Tracking with React
`QuotientProvider` tracks a page view when your app loads and after each
navigation. Auto-tracking is on by default, so no additional setup is needed.
```tsx
```
If another tool on the page already sends Quotient page views, pass
`autoTrackPageViews={false}` to avoid counting each navigation twice.
See the [React SDK](/docs/sdk/react) article for full provider setup. For manual
tracking, use `client.analytics.event()` via the `useQuotient()` hook.
## Common Patterns
### Custom Event Tracking
```javascript
import { useQuotient } from "@quotientjs/react";
function CompleteOnboardingButton() {
const { client } = useQuotient();
const handleClick = async () => {
await completeOnboarding();
void client?.analytics.event({
eventType: "custom",
customEventId: "completedOnboarding",
});
};
return ;
}
```
### Page View Tracking in a SPA
If you're not using the React SDK's `autoTrackPageViews`, you can track route
changes manually:
```javascript
import { useEffect } from "react";
import { useLocation } from "react-router-dom";
import { useQuotient } from "@quotientjs/react";
function PageTracker() {
const location = useLocation();
const { client } = useQuotient();
useEffect(() => {
void client?.analytics.event({ eventType: "pageView" });
}, [location, client]);
return null;
}
```
## Next Steps
-- End of: /sdk/analytics
-- Start of: /sdk/api-keys
---
title: API Keys
description: Understanding and managing API keys for Quotient
order: 1
---
API keys are the primary authentication mechanism for accessing the Quotient API. This guide covers the different key types, their use cases, and how to set them up correctly.
## Key Types
Quotient uses a two-tier API key system designed for different security contexts:
### Public Keys (`pk_*`)
Public keys are designed for **client-side applications** where the key is exposed in browser code or mobile apps.
**Characteristics:**
- Prefix: `pk_`
- Length: 20-40 characters after prefix
- Safe to expose in client-side code
- Limited set of scopes supported
- Origin-restricted for security
- Cannot access sensitive operations
**Allowed Endpoints:**
- `POST /api/v0/analytics` - Track events
- `POST /api/v0/audience/people` - Upsert people
- `POST /api/v0/audience/companies` - Upsert companies
- `POST /api/v0/audience/lists/:slug/people` - Add people to a list
- `DELETE /api/v0/audience/lists/:slug/people` - Remove people from a list
- `GET /api/v0/blog/*` - Retrieve blogs, authors, and tags
- `POST /api/v0/flow/:id/trigger` - Trigger a programmatic flow
- `GET /api/v0/whoami` - Verify key configuration and get client context
**Use Cases:**
- Integrating signup forms with Quotient
- Centralizing client-side analytics
- Publishing blogs and content managed by Quotient on your website
- Triggering flows from your frontend
### Private Keys (`sk_*`)
Private keys are for **server-side applications** where the key can be kept secret.
**Characteristics:**
- Prefix: `sk_`
- Length: 20-40 characters after prefix
- Must be kept secret
- Full support for all scopes
- IP address restrictions (coming soon)
**Use Cases:**
- Server-to-server integrations
- Backend services
- Data imports/exports
- Administrative operations
> **Security Warning**: Never expose private keys in client-side code, version control, or public repositories.
## Key Security Features
### Origin Restrictions (Public Keys)
Public keys can be restricted to specific origins to prevent unauthorized use if the key is stolen.
**How it works:**
1. The API checks the `Origin` header of incoming requests
2. Compares against the allowed origins list
3. Rejects requests from unauthorized origins
**Origin formats supported:**
- **Wildcard**: `*` - Allow any origin (not recommended for production)
- **Domain**: `example.com` - Matches example.com and all subdomains
- **Subdomain**: `app.example.com` - Matches only this specific subdomain
- **With protocol**: `https://app.example.com` - Matches exact protocol and domain
- **With port**: `localhost:3000` - Matches localhost on specific port
**Examples:**
```
✅ Valid origins:
- example.com
- app.example.com
- subdomain.example.com
- localhost:3000
- https://app.example.com:8080
❌ Invalid origins:
- http:// (protocol only)
- :3000 (port only)
- .com (TLD only)
```
**Matching rules:**
- `example.com` matches:
- `https://example.com`
- `https://www.example.com`
- `https://app.example.com`
- `app.example.com` matches only:
- `https://app.example.com`
- `http://app.example.com`
### Scopes
API keys support granular permission scopes. When creating a key, you assign
one or more scopes to limit what it can access. Scopes are required — there
is no implicit "full access" default; choose the smallest set your
integration needs.
| Scope | Description |
|---|---|
| `ANALYTICS_READ` | Read analytics data |
| `ANALYTICS_WRITE` | Track events |
| `AUDIENCE_PERSON_READ` | Read people |
| `AUDIENCE_PERSON_WRITE` | Create and update people |
| `AUDIENCE_COMPANY_READ` | Read companies |
| `AUDIENCE_COMPANY_WRITE` | Create and update companies |
| `AUDIENCE_LIST_READ` | Read lists and list members |
| `AUDIENCE_LIST_WRITE` | Create and update lists, add and remove members |
| `BLOG_READ` | Read blogs, authors, and tags |
| `BLOG_WRITE` | Create and update blog content |
| `FLOW_TRIGGER` | Trigger programmatic flows |
| `MEMORY_READ` | Read memory documents |
| `MEMORY_WRITE` | Create and update memory documents |
### Key Expiration
Keys can have optional expiration dates for temporary access:
- Useful for trials or time-limited integrations
- Automatically rejected after expiration
- No impact on existing data
### Usage Tracking
Each key tracks:
- **Last used**: Timestamp of most recent API call
- **Created at**: When the key was generated
- **Created by**: User who created the key
## Creating API Keys
### Via Dashboard
For now, you can only create public keys via the dashboard.
1. Navigate to **[Settings → Developers](/s/most-recent-business/settings/developers)** in your business dashboard
2. Click **"Create API Key"**
3. Configure the key:
- **Name**: Descriptive identifier (e.g., "Production Web App")
- **Description**: Optional details about usage
- **Allowed Origins**: Domains that can use this key
### Best Practices for Key Creation
#### Security Recommendations
1. **Principle of Least Privilege**
- Create separate keys for different environments
- Use the most restrictive origin settings possible
2. **Origin Restrictions**
- Never use `*` (wildcard) in production
- Be specific with subdomains
- Include ports when necessary
## Using API Keys
### In Requests
Include the API key in the `Authorization` header:
```bash
curl -X POST https://www.getquotient.ai/api/v0/analytics/web \
-H "Authorization: Bearer pk_test_1234567890abcdef" \
-H "Content-Type: application/json" \
-d '{"eventType": "pageView"}'
```
### With SDKs
```javascript
// JavaScript SDK
const quotient = await QuotientClient.init({
apiKey: 'pk_test_1234567890abcdef'
});
// React SDK
```
## Next Steps
-- End of: /sdk/api-keys
-- Start of: /sdk/audience
---
title: Audience
description: Manage people, companies, and lists using the Quotient SDK
order: 5
---
## Overview
The audience API lets you manage people, companies, lists, and custom
properties.
Both the client and server SDKs expose the audience API under `audience.*`.
The client SDK includes `audience.people` only. The server SDK adds
`audience.companies`, `audience.lists`, and `audience.properties`.
| Endpoint | API Key | Server SDK | Client SDK |
|---|---|---|---|
| Upsert person | public or private | `audience.people.upsert()` | `audience.people.upsert()` |
| Identify a person | public or private | `audience.people.identify()` | `audience.people.identify()` |
| Register for an event | public or private | `audience.people.registerForEvent()` | `audience.people.registerForEvent()` |
| Subscribe to email | public or private | `audience.people.subscribeToEmail()` | `audience.people.subscribeToEmail()` |
| Upsert company | public or private | `audience.companies.upsert()` | — |
| Upsert list | private only | `audience.lists.upsert()` | — |
| List all lists | private only | `audience.lists.list()` | — |
| Get a list | private only | `audience.lists.get()` | — |
| List people in a list | private only | `audience.lists.listPeople()` | — |
| Add people to a list | private only | `audience.lists.addPeople()` | — |
| Remove people from a list | private only | `audience.lists.removePeople()` | — |
| List custom properties | private only | `audience.properties.list()` | — |
| Create custom property | private only | `audience.properties.create()` | — |
| Update custom property | private only | `audience.properties.update()` | — |
To manage list membership from the browser, use `audience.people.upsert()`
with the `lists` parameter.
## People
### Upsert a Person
#### `audience.people.upsert(params)`
> `POST /api/v0/audience/people`
>
> **Auth:** public or private key · scope: `AUDIENCE_PERSON_WRITE`
Creates or updates a person record based on email address.
| Param | Type | Required | Description |
|---|---|---|---|
| `emailAddress` | `string` | Yes | Primary identifier |
| `emailSubscriptionStatus` | `"SUBSCRIBED" \| "UNSUBSCRIBED"` | No | Marketing email opt-in state |
| `firstName` | `string` | No | First name |
| `lastName` | `string` | No | Last name |
| `jobTitle` | `string` | No | Job title |
| `leadScore` | `number` | No | Integer lead score (default 0) |
| `lists` | `string[]` | No | List slugs to add the person to |
| `properties` | `Record` | No | Custom properties (must be pre-defined) |
```typescript
const { personId } = await client.audience.people.upsert({
emailAddress: "user@example.com",
firstName: "Jane",
lastName: "Doe",
emailSubscriptionStatus: "SUBSCRIBED",
leadScore: 50,
lists: ["newsletter", "customers"],
properties: {
plan: "pro",
signupSource: "landing-page",
},
});
```
**Email Subscription Statuses:**
- `SUBSCRIBED` - Opted in to marketing emails
- `UNSUBSCRIBED` - Opted out of marketing emails
- If not specified:
- Existing people keep their current state
- New people default based on double opt-in settings
**Returns:**
```typescript
{
personId: string; // Unique identifier (CUID format)
}
```
### Identify a Person
#### `audience.people.identify(params)`
> `POST /api/v0/audience/people/identify`
>
> **Auth:** public or private key · scope: `AUDIENCE_PERSON_WRITE`
Identifies a person by email, creating them if they don't already exist —
the same job `upsert()` does, but the intended path forward for new
integrations, since it carries lead attribution. Creating a new person fires
a `personCreated` analytics event with whatever attribution context is
available.
The client SDK attaches the visitor's current browser context (device,
session, referrer, and attribution) automatically. On the server, forward it
yourself, typically from `client.getBrowserContext()` on your frontend.
| Param | Type | Required | Description |
|---|---|---|---|
| `emailAddress` | `string` | Yes | Primary identifier |
| `firstName` | `string` | No | First name |
| `lastName` | `string` | No | Last name |
| `jobTitle` | `string` | No | Job title |
| `leadScore` | `number` | No | Integer lead score |
| `lists` | `string[]` | No | List slugs to add the person to |
| `properties` | `Record` | No | Custom properties (must be pre-defined) |
| `browserContext` | `BrowserContext` | Server SDK only | Attribution to attach if this creates a new person |
```typescript
// Browser
const { personId } = await client.audience.people.identify({
emailAddress: "user@example.com",
firstName: "Jane",
});
// Server
const { personId } = await client.audience.people.identify({
emailAddress: "user@example.com",
firstName: "Jane",
browserContext: clientBrowserContext, // forwarded from the browser client
});
```
**Returns:**
```typescript
{
personId: string;
}
```
### Register for an Event
#### `audience.people.registerForEvent(options)`
> `POST /api/v0/audience/people/register-for-event`
>
> **Auth:** public or private key · scope: `AUDIENCE_PERSON_WRITE`
Identifies a person, then registers them for a marketing event. Registration
dispatches the `marketingEventRegistration` analytics event and triggers the
event's flow automatically — no separate `analytics.event()` call is needed.
| Param | Type | Required | Description |
|---|---|---|---|
| `emailAddress` | `string` | Yes | Primary identifier |
| `eventSlug` | `string` | Yes | Slug of the marketing event to register for |
| `firstName` | `string` | No | First name |
| `lastName` | `string` | No | Last name |
| `jobTitle` | `string` | No | Job title |
| `leadScore` | `number` | No | Integer lead score |
| `lists` | `string[]` | No | List slugs to add the person to |
| `properties` | `Record` | No | Custom properties (must be pre-defined) |
| `browserContext` | `BrowserContext` | No | Attribution to attach if this creates a new person |
```typescript
const { personId, eventId, participantStatus } =
await client.audience.people.registerForEvent({
emailAddress: "user@example.com",
eventSlug: "spring-webinar",
});
```
**Returns:**
```typescript
{
personId: string;
eventId: string;
participantStatus: "INVITED" | "REGISTERED" | "ATTENDED" | "NO_SHOW" | "CANCELLED";
}
```
Fails with `404` when `eventSlug` doesn't match an event for the business, and
`400` when registration isn't allowed in the event's current state (e.g. an
ended event that doesn't accept the requested status).
### Subscribe to Email
#### `audience.people.subscribeToEmail(options)`
> `POST /api/v0/audience/people/subscribe-to-email`
>
> **Auth:** public or private key · scope: `AUDIENCE_PERSON_WRITE`
Identifies a person, then subscribes them to email, honoring the business's
double opt-in setting. If double opt-in is enabled, a new subscriber (or one
who was never subscribed) lands on `PENDING` rather than `SUBSCRIBED`. Any
other existing status is left exactly as it is; this call never overrides an
explicit unsubscribe or a compliance-managed status.
| Param | Type | Required | Description |
|---|---|---|---|
| `emailAddress` | `string` | Yes | Primary identifier |
| `firstName` | `string` | No | First name |
| `lastName` | `string` | No | Last name |
| `jobTitle` | `string` | No | Job title |
| `leadScore` | `number` | No | Integer lead score |
| `lists` | `string[]` | No | List slugs to add the person to |
| `properties` | `Record` | No | Custom properties (must be pre-defined) |
| `browserContext` | `BrowserContext` | No | Attribution to attach if this creates a new person |
```typescript
const { personId, emailSubscriptionStatus } =
await client.audience.people.subscribeToEmail({
emailAddress: "user@example.com",
});
```
**Returns:**
```typescript
{
personId: string;
emailSubscriptionStatus:
| "SUBSCRIBED"
| "UNSUBSCRIBED"
| "PENDING"
| "NOT_SUBSCRIBED"
| "REDACTED"
| "INVALID";
}
```
## Companies
### Upsert a Company
#### `audience.companies.upsert(params)`
> `POST /api/v0/audience/companies`
>
> **Auth:** public or private key · scope: `AUDIENCE_COMPANY_WRITE`
Creates or updates a company record keyed on `domain`.
| Param | Type | Required | Description |
|---|---|---|---|
| `domain` | `string` | Yes | Company domain (upsert key) |
| `name` | `string` | No | Company name |
| `description` | `string` | No | Description |
| `industries` | `string[]` | No | Industry tags |
| `totalEmployees` | `number` | No | Employee count |
| `address1` | `string` | No | Street address |
| `city` | `string` | No | City |
| `regionCode` | `string` | No | State/region code |
| `country` | `string` | No | Country code |
| `zip` | `string` | No | Postal code |
| `socialLinkLinkedIn` | `string` | No | LinkedIn URL |
| `properties` | `Record` | No | Custom properties (must be pre-defined) |
```typescript
const { companyId } = await client.audience.companies.upsert({
domain: "acme.com",
name: "Acme Corp",
description: "Makes everything",
industries: ["manufacturing"],
totalEmployees: 500,
properties: {
arr: 1200000,
fundingStage: "Series B",
},
});
```
**Returns:**
```typescript
{
companyId: string; // Unique identifier (CUID format)
}
```
Domain is not required to be unique. If exactly one company matches `domain`,
it's updated; if none match, one is created. If more than one company shares
the same domain, the upsert fails with a `409`:
```typescript
{
domain: string; // The domain that matched more than one company
matchCount: number; // How many companies matched
matchingCompanyIds: string[]; // Ids of the matching companies
}
```
## Lists
The Lists API lets you create and manage audience lists programmatically.
Lists are identified by a unique slug and can contain people identified by
either their person ID or email address.
All list operations require a private API key. List membership
changes (`addPeople`, `removePeople`) are not safe to expose on a
public key, so they're server-side only.
```typescript
import { QuotientServer } from "@quotientjs/server";
const client = new QuotientServer({
privateKey: "sk_your_private_api_key",
});
```
### Create or Update a List
#### `audience.lists.upsert(options)`
> `POST /api/v0/audience/lists`
>
> **Auth:** private key only · scope: `AUDIENCE_LIST_WRITE`
The **slug** is always the upsert key — you either provide it directly, or
it gets derived from the name.
| Param | Type | Required | Description |
|---|---|---|---|
| `name` | `string` | One of `name` or `slug` | List name (slug auto-derived if slug omitted) |
| `slug` | `string` | One of `name` or `slug` | Explicit slug to target |
| `description` | `string` | No | List description |
```typescript
// By name — slug is auto-generated ("newsletter-subscribers")
await client.audience.lists.upsert({
name: "Newsletter Subscribers",
description: "People who opted into our weekly newsletter",
});
// By slug — target an existing list directly
await client.audience.lists.upsert({
slug: "newsletter-subscribers",
description: "Updated description",
});
// By slug + name — target by slug, rename the list
await client.audience.lists.upsert({
slug: "newsletter-subscribers",
name: "Weekly Newsletter",
});
```
**Upsert behavior:**
| Input | Lookup key | Not found | Found |
|---|---|---|---|
| `{ name }` | `generateSlug(name)` | Create with name + generated slug | Update name |
| `{ name, description }` | `generateSlug(name)` | Create with both | Update name + description |
| `{ slug }` | slug | Create (name defaults to slug) | No-op |
| `{ slug, name }` | slug | Create with name + slug | Update name |
| `{ slug, description }` | slug | Create (name defaults to slug) | Update description |
| `{ slug, name, description }` | slug | Create with all fields | Update name + description |
**Returns:**
```typescript
{
listId: string;
name: string;
slug: string;
}
```
### List All Lists
#### `audience.lists.list(options?)`
> `GET /api/v0/audience/lists`
>
> **Auth:** private key only · scope: `AUDIENCE_LIST_READ`
| Param | Type | Required | Description |
|---|---|---|---|
| `search` | `string` | No | Filter by name |
| `page` | `number` | No | Page number (default 1) |
| `limit` | `number` | No | Results per page (default 20) |
```typescript
const { lists, pageData } = await client.audience.lists.list({
search: "newsletter",
page: 1,
limit: 20,
});
```
**Returns:**
```typescript
{
lists: {
id: string;
name: string;
slug: string;
description: string | null;
peopleCount: number;
createdAt: string;
updatedAt: string;
}[];
pageData: {
page: number;
limit: number;
total: number;
isNextPageAvailable: boolean;
};
}
```
### Get a Single List
#### `audience.lists.get(options)`
> `GET /api/v0/audience/lists/{slug}`
>
> **Auth:** private key only · scope: `AUDIENCE_LIST_READ`
| Param | Type | Required | Description |
|---|---|---|---|
| `slug` | `string` | Yes | List slug |
```typescript
const { list } = await client.audience.lists.get({
slug: "newsletter-subscribers",
});
```
**Returns:**
```typescript
{
list: {
id: string;
name: string;
slug: string;
description: string | null;
peopleCount: number;
createdAt: string;
updatedAt: string;
};
}
```
### List People in a List
#### `audience.lists.listPeople(options)`
> `GET /api/v0/audience/lists/{slug}/people`
>
> **Auth:** private key only · scope: `AUDIENCE_LIST_READ`
| Param | Type | Required | Description |
|---|---|---|---|
| `listSlug` | `string` | Yes | List slug |
| `search` | `string` | No | Filter by email |
| `page` | `number` | No | Page number (default 1) |
| `limit` | `number` | No | Results per page (default 20) |
```typescript
const { people, pageData } = await client.audience.lists.listPeople({
listSlug: "newsletter-subscribers",
search: "jane",
page: 1,
limit: 20,
});
```
**Returns:**
```typescript
{
people: {
personId: string;
emailAddress: string;
firstName: string | null;
lastName: string | null;
}[];
pageData: {
page: number;
limit: number;
total: number;
isNextPageAvailable: boolean;
};
}
```
### Add People to a List
#### `audience.lists.addPeople(options)`
> `POST /api/v0/audience/lists/{slug}/people`
>
> **Auth:** private key only · scope: `AUDIENCE_LIST_WRITE`
Add up to 100 people per request. Each entry can reference an existing person
by ID, or provide an email address to upsert a person and add them in one call.
| Param | Type | Required | Description |
|---|---|---|---|
| `listSlug` | `string` | Yes | List slug |
| `people` | `AddPersonEntry[]` | Yes | Array of people to add (max 100) |
Each entry in `people` is one of:
| Param | Type | Required | Description |
|---|---|---|---|
| `personId` | `string` | Yes (if no email) | Existing person ID |
| `emailAddress` | `string` | Yes (if no ID) | Email to upsert |
| `firstName` | `string` | No | First name (with email only) |
| `lastName` | `string` | No | Last name (with email only) |
| `jobTitle` | `string` | No | Job title (with email only) |
| `leadScore` | `number` | No | Lead score (with email only) |
| `properties` | `Record` | No | Custom properties (with email only) |
```typescript
await client.audience.lists.addPeople({
listSlug: "newsletter-subscribers",
people: [
{ personId: "clx..." },
{
emailAddress: "jane@example.com",
firstName: "Jane",
lastName: "Doe",
properties: { plan: "pro" },
},
],
});
```
**Returns:**
```typescript
{
added: number;
listSlug: string;
listId: string;
}
```
### Remove People from a List
#### `audience.lists.removePeople(options)`
> `DELETE /api/v0/audience/lists/{slug}/people`
>
> **Auth:** private key only · scope: `AUDIENCE_LIST_WRITE`
Remove up to 100 people per request. Each entry can reference a person by ID
or by email address. This operation is idempotent — removing a person who is
not in the list (or referencing an email that doesn't exist) is a no-op.
| Param | Type | Required | Description |
|---|---|---|---|
| `listSlug` | `string` | Yes | List slug |
| `people` | `RemovePersonEntry[]` | Yes | Array of people to remove (max 100) |
Each entry in `people` is one of:
| Param | Type | Description |
|---|---|---|
| `personId` | `string` | Existing person ID |
| `emailAddress` | `string` | Person's email address |
```typescript
await client.audience.lists.removePeople({
listSlug: "newsletter-subscribers",
people: [
{ personId: "clx..." },
{ emailAddress: "jane@example.com" },
],
});
```
**Returns:**
```typescript
{
removed: number;
listSlug: string;
listId: string;
}
```
## Custom Properties
Custom properties are the fields you define on people, companies, and deals
beyond the built-in ones. These endpoints manage the property *definitions* —
the values themselves are written through `audience.people.upsert()` /
`audience.companies.upsert()` `properties` payloads, which validate against
the definitions.
Every definition has an `entityType` (`"person"`, `"company"`, or `"deal"`),
an immutable alphanumeric `id` (the key used in `properties` payloads), an
immutable `datatype`, and a `readOnly` flag. `SINGLE_SELECT` and
`MULTI_SELECT` datatypes carry `allowedValues` — the closed set of allowed
options, always at least 2.
### List Custom Properties
#### `audience.properties.list(options)`
> `GET /api/v0/audience/properties`
>
> **Auth:** private key only · scope: `AUDIENCE_PROPERTY_READ`
| Param | Type | Required | Description |
|---|---|---|---|
| `entityType` | `"person" \| "company" \| "deal"` | Yes | Which entity's definitions to list |
```typescript
const { properties } = await client.audience.properties.list({
entityType: "person",
});
```
**Returns:**
```typescript
{
properties: Array<{
id: string;
businessId: string;
entityType: "person" | "company" | "deal";
displayName: string;
description: string | null;
datatype: string; // e.g. "STRING", "NUMBER", "SINGLE_SELECT", ...
allowedValues?: string[]; // present only on select datatypes
readOnly: boolean;
}>;
}
```
### Create a Custom Property
#### `audience.properties.create(options)`
> `POST /api/v0/audience/properties`
>
> **Auth:** private key only · scope: `AUDIENCE_PROPERTY_WRITE`
| Param | Type | Required | Description |
|---|---|---|---|
| `entityType` | `"person" \| "company" \| "deal"` | Yes | Which entity the property is defined for |
| `id` | `string` | Yes | API name — alphanumeric, unique per entity type, immutable |
| `displayName` | `string` | Yes | Human-readable name shown in the UI |
| `datatype` | `string` | Yes | Value type (`STRING`, `NUMBER`, `BOOLEAN`, `DATE`, `SINGLE_SELECT`, ...) — immutable |
| `allowedValues` | `string[]` | Yes (select datatypes) | Allowed options — at least 2; forbidden for other datatypes |
| `readOnly` | `boolean` | No | Read-only properties reject value writes (default false) |
```typescript
const { property } = await client.audience.properties.create({
entityType: "person",
id: "plan",
displayName: "Plan",
datatype: "SINGLE_SELECT",
allowedValues: ["free", "pro", "enterprise"],
});
```
**Returns:**
```typescript
{
property: CustomPropertyDefinition; // same shape as the list items
}
```
Fails with `409` when the id already exists for the entity type or collides
with a built-in field, and `422` when the id isn't alphanumeric or a select
datatype has fewer than 2 options.
### Update a Custom Property
#### `audience.properties.update(options)`
> `PATCH /api/v0/audience/properties/:propertyId`
>
> **Auth:** private key only · scope: `AUDIENCE_PROPERTY_WRITE`
Only `displayName`, `readOnly`, and (for select datatypes) appending new
options are supported — `id` and `datatype` are immutable, and existing
options can't be renamed or removed.
| Param | Type | Required | Description |
|---|---|---|---|
| `propertyId` | `string` | Yes | The property's id (API name) |
| `entityType` | `"person" \| "company" \| "deal"` | Yes | Which entity the property is defined for |
| `displayName` | `string` | No | New display name |
| `readOnly` | `boolean` | No | New read-only flag |
| `addAllowedValues` | `string[]` | No | NEW options to append (select datatypes only; an exact re-add is a no-op, a case-variant of an existing option is rejected) |
```typescript
const { property } = await client.audience.properties.update({
propertyId: "plan",
entityType: "person",
addAllowedValues: ["enterprise-plus"],
});
```
**Returns:**
```typescript
{
property: CustomPropertyDefinition; // same shape as the list items
}
```
Fails with `404` when the property doesn't exist for the entity type, and
`422` when `addAllowedValues` targets a non-select datatype.
## Common Patterns
### User Identification on Signup
```javascript
async function identifyUser(user) {
const { personId } = await client.audience.people.upsert({
emailAddress: user.email,
firstName: user.firstName,
lastName: user.lastName,
emailSubscriptionStatus: "SUBSCRIBED",
leadScore: user.leadScore ?? 0,
lists: ["customers", "newsletter"],
properties: {
plan: user.subscription,
signupDate: new Date(),
lastLogin: new Date(),
totalPurchases: user.purchaseCount,
},
});
console.log(`User identified: ${personId}`);
}
```
### Contact Form Capture
```javascript
async function handleContactForm(formData) {
try {
await client.audience.people.upsert({
emailAddress: formData.email,
firstName: formData.firstName,
lastName: formData.lastName,
lists: ["leads"],
properties: {
message: formData.message,
source: "contact-form",
submittedAt: new Date(),
},
});
void client.analytics.event({
eventType: "custom",
customEventId: "contact_form_submitted",
});
} catch (error) {
console.error("Failed to save lead:", error);
}
}
```
Create `contact_form_submitted` in Quotient before sending it. See
[Custom Events](/docs/analytics/custom-events) for the complete browser
workflow.
### Syncing a List from an External Source
```typescript
const client = new QuotientServer({ privateKey: "sk_..." });
// Ensure the list exists
await client.audience.lists.upsert({
name: "Active Customers",
description: "Synced from billing system",
});
// Add people in batches of 100
const customers = getActiveCustomers(); // your data source
for (let i = 0; i < customers.length; i += 100) {
const batch = customers.slice(i, i + 100);
await client.audience.lists.addPeople({
listSlug: "active-customers",
people: batch.map((c) => ({
emailAddress: c.email,
firstName: c.firstName,
lastName: c.lastName,
properties: {
plan: c.plan,
mrr: c.mrr,
},
})),
});
}
```
## Next Steps
-- End of: /sdk/audience
-- Start of: /sdk/blog
---
title: Blog
description: Retrieve and render blog content using the Quotient SDK
order: 7
---
## Overview
The blog API lets you retrieve published blog posts, authors, and tags from
your Quotient blog. All endpoints are read-only and work with both public and
private API keys.
| Endpoint | API Key | Server SDK | Client SDK |
|---|---|---|---|
| Get blog post | public or private | `blog.get()` | `blog.get()` |
| List blog posts | public or private | `blog.list()` | `blog.list()` |
| List authors | public or private | `blog.listAuthors()` | `blog.listAuthors()` |
## Get a Blog Post
#### `blog.get(options)`
> `GET /api/v0/blog/{slug}`
>
> **Auth:** public or private key · scope: `BLOG_READ`
| Param | Type | Required | Description |
|---|---|---|---|
| `slug` | `string` | Yes | Blog post slug |
| `rawHtml` | `boolean` | No | Return pre-rendered HTML |
```typescript
const { blog } = await client.blog.get({
slug: "my-first-post",
rawHtml: true,
});
```
**Returns:**
```typescript
{
blog: {
id: string;
title: string;
slug: string;
content: JSON;
dominantImageUrl?: string | null;
publishDate: Date | null;
rawHtml?: string | null;
authors: {
id: string;
name: string;
emailAddress?: string | null;
avatarUrl?: string | null;
}[];
metaDescription: string | null;
tags: {
id: string;
name: string;
description?: string | null;
}[];
};
}
```
## List Blog Posts
#### `blog.list(options?)`
> `GET /api/v0/blog/list`
>
> **Auth:** public or private key · scope: `BLOG_READ`
| Param | Type | Required | Description |
|---|---|---|---|
| `authorIds` | `string[]` | No | Filter by author IDs |
| `tagIds` | `string[]` | No | Filter by tag IDs |
| `statuses` | `("DRAFT" \| "SCHEDULED" \| "PUBLISHED")[]` | No | Filter by status |
| `search` | `string` | No | Search by title |
| `page` | `number` | No | Page number (default 1) |
| `limit` | `number` | No | Results per page (default 50) |
```typescript
const { blogs, pageData } = await client.blog.list({
statuses: ["PUBLISHED"],
search: "marketing",
page: 1,
limit: 20,
});
```
**Returns:**
```typescript
{
blogs: {
id: string;
title: string;
slug: string;
content: JSON;
dominantImageUrl?: string | null;
publishDate: Date | null;
authors: {
id: string;
name: string;
emailAddress?: string | null;
avatarUrl?: string | null;
}[];
metaDescription: string | null;
tags: {
id: string;
name: string;
description?: string | null;
}[];
}[];
pageData: {
page: number;
limit: number;
total: number;
isNextPageAvailable: boolean;
};
}
```
## List Authors
#### `blog.listAuthors(options?)`
> `GET /api/v0/blog/authors`
>
> **Auth:** public or private key · scope: `BLOG_READ`
| Param | Type | Required | Description |
|---|---|---|---|
| `search` | `string` | No | Filter by name |
| `page` | `number` | No | Page number (default 1) |
| `limit` | `number` | No | Results per page (default 10) |
```typescript
const { authors, pageData } = await client.blog.listAuthors({
search: "jane",
page: 1,
limit: 10,
});
```
**Returns:**
```typescript
{
authors: {
id: string;
name: string;
emailAddress?: string | null;
avatarUrl?: string | null;
}[];
pageData: {
page: number;
limit: number;
total: number;
isNextPageAvailable: boolean;
};
}
```
## Caching in Next.js
Blog content is a natural fit for caching. Posts change infrequently, so
re-fetching them on every request is wasteful — especially on high-traffic
pages like a blog index or a sitemap. Each server blog method accepts an
optional second argument, `fetchOptions`, which is forwarded to `fetch`. In a
Next.js app you can use it to opt into Incremental Static Regeneration instead
of fetching fresh data every time.
For example, a sitemap that lists every published post only needs to refresh
every hour or so:
```typescript
const { blogs } = await client.blog.list(
{ statuses: ["PUBLISHED"], limit: 1000 },
{ cache: "force-cache", next: { revalidate: 3600 } },
);
```
See [Customizing fetch behavior](/docs/sdk) for the full list of options you can
pass and the fields the SDK reserves for itself.
## Rendering
The `@quotientjs/react` package provides a `` component that renders
blog content into HTML. It takes the `content` JSON from `blog.get()` and
produces unstyled semantic HTML elements.
### Basic Usage
```tsx
import { Blog } from "@quotientjs/react";
import { QuotientServer } from "@quotientjs/server";
// app/blog/[slug]/page.tsx
export default async function BlogPost({
params,
}: {
params: { slug: string };
}) {
const client = new QuotientServer({
privateKey: process.env.QUOTIENT_PRIVATE_KEY!,
});
const { blog } = await client.blog.get({ slug: params.slug });
return ;
}
```
### Styling
The `` component renders unstyled HTML with default class names on
each element (`quotient-p`, `quotient-h1`, `quotient-a`, etc.). There are
three ways to style blog content:
**1. Target default classes in CSS**
```css
.quotient-p { line-height: 1.75; }
.quotient-h2 { margin-top: 2rem; }
.quotient-a { color: blue; text-decoration: underline; }
```
**2. Override classes via `elementClassName`**
```tsx
```
**3. Tailwind Typography plugin**
```tsx
```
### Available Class Targets
| Element | Default Class |
|---|---|
| `` | `quotient-strong` |
| `` | `quotient-em` |
| `` | `quotient-u` |
| `` | `quotient-a` |
| `
Real-time collaboration infrastructure. Enables collaborative editing
features in WYSIWYG editors.
## Data Processing Compliance
All subprocessors are carefully vetted for security and compliance. Where required by applicable data protection laws, we maintain data processing agreements with our subprocessors that include:
- Appropriate technical and organizational security measures
- Confidentiality commitments
- Data protection compliance obligations
- Terms governing data transfers and subprocessing
## Updates to This List
This subprocessor list is current as of the date of this document. Quotient reserves the right to add, remove, or replace subprocessors as needed to improve our services. Material changes to this list will be communicated to merchants in accordance with our Terms of Service.
If you have questions about our subprocessors or data processing practices, please contact us at support@getquotient.ai.
-- End of: /trust-security/subprocessors
-- Start of: /working-with-ai/index
---
title: Working with AI
description: How to get the most out of chatting with Quotient
order: 1
---
You can chat with Quotient in plain English, just like you would with a coworker. Tell it what you want, and it will help you get it done. If you've used products like ChatGPT or Claude, the experience will feel familiar.
However, working with AI is different from working with a human in a few key ways. The most important concept to understand is **context.**
## Context and Tools
"Context" refers to the information that is available to Quotient. Unlike humans, Quotient starts each conversation fresh — it doesn't remember what you told it yesterday. It has to be explicitly provided with the information it needs to do its job.
This means you should be explicit about what you want and provide all necessary context in each conversation. Knowing what context Quotient has and doesn't have will help you interact with it more effectively.
When you talk to Quotient, its context will automatically include…
- Information about your brand saved in Quotient's **[memory](/docs/working-with-ai/memory)**
- The conversation history within that chat thread
- An understanding of the Quotient platform itself
- Specialized knowledge relevant to the task at hand (e.g. when writing a blog, Quotient draws on expertise in SEO-optimized content)
However, Quotient's context does _not_ include...
- Knowledge of current events, like today's front page news or what's currently trending in your industry
- Any information about your brand or business that isn't saved in memory
- Your past conversations (if you tell Quotient about a new product feature in one conversation, it won't know about it in future conversations unless you ask Quotient to save it to memory)
To get additional information, Quotient can use **tools** to look things up. Tools allow Quotient to interact with the outside world, including the Quotient platform, the open internet, and other integrated systems.
Quotient can use tools to find information to add to its existing context, such as…
- Searching the web and visiting web pages
- Looking up a person or company from your Quotient audience
- Looking up all currently active campaigns in Quotient
In addition to looking up information, tools can also perform actions, such as…
- Creating a new campaign
- Editing a blog
- Deleting an email broadcast
## @ Mentioning Objects
You can @ mention **objects** in Quotient, such as Campaigns, Email Broadcasts, Blogs, Segments, and Email Templates.
Mentioning objects will automatically include all of the data about that object into Quotient's context. You can think of this like sharing a URL with a coworker. Your coworker can click into the URL, give it a quick read, and understand what you're talking about. But without the URL, they might be confused and not understand the context.
Here are some examples of when you might @ mention an object:
- If you're asking Quotient to use a specific email template as part of a flow
- If you're asking Quotient to send an email to a specific segment
- If you want Quotient to use a specific asset as the thumbnail image for a blog
## Managing Threads
Each conversation in Quotient is called a "thread". Within a given thread, Quotient will recall the entire conversation history, but it won't recall conversations from _other_ threads.
When a thread gets too large or covers too many topics, it tends to confuse or overwhelm the AI. Long threads can be overwhelming for humans too. (No one likes looking at a Slack thread with 150 responses, or an email chain that's 80 replies long.)
To get the best performance out of Quotient, it's best to keep threads scoped to a single task or set of related tasks. A good rule of thumb is to create one thread per **deliverable** — i.e. a single thread for each blog, campaign, email broadcast, etc.
Sometimes it makes sense to group related deliverables into a single thread. For example, you might be working on a blog post as well as an email broadcast announcing the new post to your subscribers. In this case, it might make sense to create both deliverables in the same thread.
On the other hand, if you have a completely new, unrelated request, it's best to start a fresh thread to begin working on it.
## Memories
Although Quotient doesn't naturally remember past conversations the way people do, it can save **[memories](/s/most-recent-business/memory)** that it draws on in future ones. This is how Quotient learns your business's particular preferences and workflows. If you want Quotient to remember something, just tell it to "please remember this going forward."
Common examples of memories include…
- Which email templates should be used as a starting point when creating new broadcasts
- Which segments or lists should be used in flows and email broadcasts
- Preferences about campaign management (e.g. "campaigns should always contain one email broadcast per blog post")
Memory also holds core information about your brand, like your ideal customer profile and brand voice guidelines. See [Memory](/docs/working-with-ai/memory) for what to save and how to organize it.
## Choosing an AI Model
Quotient can run on models from several AI providers, including Anthropic's Claude, OpenAI's GPT, Google's Gemini, and xAI's Grok. You can pick one from the model picker in the chat box:
Each message in a thread can use a different model, and the conversation history carries over when you switch.
If you're not sure which to pick, leave it on **Auto**. We regularly test leading models on everyday marketing work like campaign planning, copywriting, and research, and Auto uses whichever one currently does best.
The picker remembers your choice. An existing thread stays on the last model it used, and a new thread starts with the last model you picked. That default is saved in your browser for each business, so it isn't shared with your teammates.
Models with a **Pro** badge, like Claude Opus and GPT-5.6 Sol, are premium models. They're available on the Starter plan and above and use more AI credits per message. If your plan changes and you lose access to them, the picker switches back to Auto. See [Plans and Billing](/docs/plans-and-billing) for how credits work, and check [Settings > Usage](/s/most-recent-business/settings/usage) to track your usage.
-- End of: /working-with-ai/index
-- Start of: /working-with-ai/jobs
---
title: Jobs
description: Put recurring work on a schedule so Quotient does it for you
order: 2
---
Quotient can run marketing tasks for you on a schedule. For example, you might
want a daily list of new signups worth a follow-up, a weekly summary of campaign
performance, or a monthly draft of your customer newsletter.
A **job** is one of these recurring tasks. You write the instructions once and
pick a schedule, and Quotient carries out the instructions each time the job is
due, without anyone having to open a chat.
## Creating a Job
The easiest way to create a job is to ask Quotient. Describe what you want done
and how often. Here are a few examples:
Quotient creates the job from your request, including the instructions it will
follow on every run. Since you won't be there to clarify when the job runs, it's
worth being specific. "Summarize campaign performance" works, but "compare each
active campaign's email clicks and website sessions to the previous week" gets
you a more useful summary. You can @ mention objects in your request, like a
particular campaign or segment, and the job will refer to them on every run.
You can also create a job yourself on the
[Jobs](/s/most-recent-business/agent-jobs) page with the **Create Job** button.
There you write the instructions, attach files if the job needs them, choose
which AI model the job starts with, and set the schedule.
## Schedules
On the Jobs page, you can schedule a job to run daily, weekly on a given day, or
monthly on a given date, at a time of your choosing. Times are in your
business's time zone. When you ask Quotient instead, you can describe more
specific patterns in plain language, like "every weekday at 8am" or "every other
hour during business hours".
Jobs start within a few minutes of their scheduled time. When you ask Quotient
for a job, mention your time zone ("9am Eastern") so there is no ambiguity. Each
job on the Jobs page shows its schedule and when it will run next, which is a
quick way to confirm Quotient got it right.
## What Happens When a Job Runs
Each run starts a new chat thread, as if the job's owner had typed the
instructions into a fresh conversation. Quotient can do anything it does in a
regular chat, like run reports, search the web, or draft content. These threads
appear in your chat history, labeled with the job's name.
When a run finishes, Quotient notifies the job's owner with a short summary and
links to anything it created. Notifications appear in Quotient, and by email and
[Slack](/docs/integrations/slack) if you've turned those on in your
[notification settings](/s/most-recent-business/settings/notifications). If a
run fails, the owner gets a notification with a link to the thread.
The owner is whoever created the job, unless you choose someone else. Teammates
can click the bell icon on a job to get notified too.
Each run uses AI credits like a regular conversation. Jobs are included on every
paid plan. If your plan stops including them, your jobs are saved but don't run
until that's resolved. See [Plans and Billing](/docs/plans-and-billing).
## Changing or Deleting a Job
To change a job, ask Quotient to update it ("move my Monday report to 8am", or
"also include social post engagement in the weekly summary"), or click the job
on the Jobs page to edit its name, instructions, schedule, and owner. Changes
take effect the next time the job runs.
Hover over a job to see two more actions. **Run Now** runs the job right away
and opens the resulting thread, which is handy for testing new instructions
without waiting for the schedule. **Delete** stops the job for good. There's no
pause button, so if you only want a job to stop for a while, copy its
instructions before you delete it and create it again when you need it.
A few tips for getting the most out of jobs:
- Run a new job once with **Run Now** before you rely on it, and adjust the
instructions until the output looks right.
- Say what you want delivered. "Tell me the three campaigns with the biggest
drop in clicks" gets a sharper result than "check on campaigns".
- Keep each job to one task. Two focused jobs are easier to read and to fix than
one job that does everything.
-- End of: /working-with-ai/jobs
-- Start of: /working-with-ai/memory
---
title: Memory
description: How Quotient learns about your brand, preferences, and workflows
order: 1
---
To do great marketing, Quotient needs context about your business — the same kind of context you'd give a new hire before they could do useful work. **[Memory](/s/most-recent-business/memory)** is where that context lives.
Memory is a collection of documents that Quotient draws on whenever it writes content, proposes campaigns, or gives strategic advice. The more you teach Quotient about your business, the more relevant and on-brand its output becomes.
This isn't so different from a human marketing agency. To do good work, an agency spends time learning your brand, your customers, and how you like to operate. The same goes for Quotient — except instead of onboarding calls and brand decks, the knowledge lives in memory, and Quotient can draw on all of it instantly.
## What Goes in Memory
Memory is broader than just brand information. It captures anything that helps Quotient do better marketing for your business. Most memories fall into three categories.
**Brand fundamentals.** Who you are, what you sell, who you sell to, and how you talk about it. Think product overviews, ideal customer profiles, competitive positioning, and brand voice guidelines. This is typically the first thing you'll build when you get started with Quotient.
**Workflows and playbooks.** How your team actually gets marketing done. If you have a specific process for running product launches, publishing a weekly changelog, or planning quarterly campaigns, you can capture that in a memory document. When you later ask Quotient to kick off a product launch, it already knows what deliverables to produce, what the campaign structure should look like, and which channels to use — because your playbook told it so.
**Preferences.** Individual or team-level preferences about how work should be done. For example, you might create a memory that describes how a specific team member likes to write social media posts — their preferred tone, length, and formatting. Quotient is often smart enough to create these on your behalf. If you say something like "going forward, I want my blog posts to always include a summary at the top," Quotient will save that as a memory automatically.
## Common Memory Documents
Here are examples of documents that most businesses should have:
- **Ideal Customer Profile (ICP):** Your target customers — demographics, pain points, decision-making process, and what drives them to your solution. Helps Quotient create more targeted content.
- **Competitors and Battle Cards:** Profiles of your main competitors — positioning, pricing, strengths, weaknesses, and key differentiators. Enables Quotient to highlight your unique advantages.
- **Product Overview:** Core functionality, key features, integrations, and what makes your product different. Ensures Quotient accurately represents your capabilities.
- **Value Proposition:** Your main benefits and supporting pillars — the core reasons customers choose you. Gives Quotient consistent messaging frameworks.
- **Brand Voice and Style Guide:** Your brand personality, tone, writing preferences, and communication style, with examples of on-brand vs. off-brand copy.
- **Customer Success Stories:** Case studies, testimonials, and key metrics. Gives Quotient concrete proof points to draw on.
- **Messaging Framework:** Tested headlines, taglines, content themes, and words or phrases to avoid.
- **Campaign Playbooks:** Step-by-step workflows for recurring campaigns — a product launch playbook, a webinar planning checklist, or a process for assembling weekly newsletters. These help Quotient follow your team's established process rather than improvising from scratch.
## Pinned Memories
Not all memories are surfaced to Quotient at all times.
When you ask Quotient to do something, the system identifies
which memories are most relevant to the task at hand and
pulls them in automatically. This keeps Quotient focused
and avoids overwhelming it with context that isn't useful for
the current job.
**Pinned memories** override this behavior.
When you pin a memory, it is always visible to Quotient — regardless of the task.
This is useful for foundational context that Quotient needs in every
interaction, not just specific ones.
Good candidates for pinning:
- **Brand Voice and Style Guide:** so every piece of content stays on-brand
- **Value Proposition:** so Quotient always knows how to position your product
- **Key Preferences:** company-wide rules like "never use the word 'synergy'"
or "always link to the pricing page in bottom-of-funnel content"
You can pin or unpin a memory at any time from the memory detail page.
Pinned memories are marked with a pin icon in the memory list so you can
see at a glance which ones are always active.
Pin sparingly — if everything is pinned, the benefit is lost.
Memories that are only relevant to specific channels or tasks
(like an email-specific style guide or a single campaign playbook)
are better left unpinned. Quotient's relevance system will still
surface them when they're needed. Reserve pinning for the handful
of documents that truly represent your business fundamentals.
## Tags
Tags help you organize memories by area or by author,
so that Quotient can more easily identify which memories are relevant to each task.
There are two types of tags: **platform tags** and **user tags**.
### Platform Tags
Platform tags correspond to a platform area or topic. They help Quotient understand which memories apply to which kind of work. When Quotient is working on a task tied to a specific area, it will prioritize memories with matching tags — so the right guidelines show up at the right time without you having to think about it.
The available platform tags are:
| Tag | Use it for |
|---|---|
| **email** | Email campaign preferences — subject line style, send cadence, CTA placement |
| **blog** | Blog writing guidelines — structure, length, formatting conventions |
| **social** | Social media preferences — tone, hashtags, platform-specific conventions |
| **tone** | General voice and tone guidelines that apply across channels |
| **audience** | Target audience definitions and segmentation context |
| **brand** | Core brand identity — positioning, messaging, visual guidelines |
| **competitors** | Competitive intelligence — battle cards, positioning against alternatives |
| **products** | Product details — features, use cases, pricing context |
**Example:** You create a memory called "Email Best Practices" that describes your
preferred subject line style, send cadence, and CTA placement.
You tag it with **email**. Now, whenever Quotient drafts an email
campaign, this memory is automatically prioritized — but it won't
clutter the context when Quotient is writing a blog post.
### User Tags
User tags correspond to a specific user or author in Quotient.
These are useful when different team members have different
preferences or responsibilities.
**Example:** Your teammate Sarah prefers a conversational,
first-person tone in her blog posts, while your teammate
James writes in a more formal, third-person style. You create
separate "Writing Preferences" memories for each and tag them
with **Sarah** and **James** respectively. When Sarah asks
Quotient to draft a post, her preferences are applied
automatically — and the same for James.
## Building Your Memory
Building memory is not a one-time activity. It evolves alongside your business,
and as your product, positioning, and strategy change, your memory should too.
Here are the most common ways to get started.
### Ask Quotient to Interview You
This is often the best starting point. Ask Quotient to conduct an interview
about your brand, and it will ask the right questions to help you articulate
your ICP, value proposition, competitive positioning, and more. It's a great way
to get knowledge that's locked in your head down on paper.
### Share Your Website
Tell Quotient which URLs to look at, and it will visit your site, read about
your product and company, and use what it finds to bootstrap your memory. Note
that Quotient can only access public URLs.
### Upload Documents
If you have PDFs, Word documents, or slide decks about your brand, upload them
to chat and ask Quotient to synthesize them into memory documents. Copy and
paste works too.
### Ask Quotient to Research
Tell Quotient to search the web on your behalf. A common use case is researching
competitors and building battle cards that assess your strengths and weaknesses
relative to each one.
### Connect External Tools
Useful context often lives in other systems, like product briefs in Notion,
feature specs in Linear, or messaging docs in Google Drive. You can use
[MCP connections](/docs/mcp/connecting-tools) to give Quotient access to these
tools, making it easy to pull relevant context into memory.
Think of memory as a living wiki for your business: the single source of truth
for everything Quotient needs to know to do great work.
-- End of: /working-with-ai/memory
-- Start of: /analytics/custom-events/index
---
title: Custom Events
description:
Record important website conversions and connect them to the marketing that
drove them
order: 4
---
Quotient's tracking tag records page views and sessions automatically, but not
the other things people do on your site, like clicking a button or submitting a
form. Those are often the actions that matter most: requesting a demo,
downloading a whitepaper, watching a video, or logging into your product.
To record these actions, you create **custom events** in Quotient and send them
from your website. Quotient then attributes each one, often called a conversion,
to the person who performed it and to the campaign content that brought them to
your site, so you can measure how many conversions your marketing drove.
When your site records a custom event, Quotient includes the visitor's current
session and attribution context. This lets you answer questions such as "Which
campaign drove the most demo requests?" instead of stopping at clicks and page
views.
This guide covers events that happen in a visitor's browser. If the conversion
completes on your server instead, such as an account created in an OAuth
callback, see
[Server-Side Conversions](/docs/analytics/custom-events/server-side-conversions).
Before you begin,
[install Quotient website tracking](/docs/analytics/on-site-tracking/custom-website)
on your site.
## Create the Custom Event in Quotient
Open
[Analytics → Custom Events](/s/most-recent-business/analytics/custom-events) and
click **Create Custom Event**. Each custom event has three fields:
- **Display Name** is the readable name shown in Quotient, such as "Requested
Demo."
- **Event ID** is the value your website sends, such as `requested_demo`. It
must start with a letter and contain only letters, numbers, and underscores.
- **Description** explains what the event means and when your site should send
it.
The event ID cannot be changed after you create the event, although you can edit
its display name and description. Choose one ID and reuse it everywhere that
records the same action.
You must create the event before your website sends it. Quotient rejects an
event ID that is not registered for your business.
## Record the Completed Action
Send the event after the action succeeds. For example, a demo-request event
should run after the form submission is accepted, not when someone first clicks
the submit button.
```javascript
async function handleDemoRequest(formData) {
const response = await fetch("/api/demo-requests", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(formData),
});
if (!response.ok) {
showSubmissionError();
return;
}
showSuccess();
void client.analytics.event({
eventType: "custom",
customEventId: "requested_demo",
});
}
```
Replace `requested_demo` with the event ID you created in Quotient. The browser
SDK sends analytics in the background, so the tracking request does not hold up
the form's success state.
The example uses the `client` created by `@quotientjs/client`. In a React
application, get the same client from the
[`useQuotient()` hook](/docs/sdk/react).
## If the Form Also Adds the Person to Quotient
It's common for a form to do two things at once:
[identify the person](/docs/analytics/identifying-users) and record a custom
event. In that case, wait for Quotient to identify the person before recording
the event:
```javascript
async function handleDemoRequest(formData) {
try {
await client.audience.people.identify({
emailAddress: formData.email,
firstName: formData.firstName,
lastName: formData.lastName,
});
} catch (error) {
console.error("Failed to save lead", error);
showSubmissionError();
return;
}
showSuccess();
void client.analytics.event({
eventType: "custom",
customEventId: "requested_demo",
});
}
```
`identify()` returns only after Quotient has saved the person and added their ID
to the browser client. The custom event sent immediately afterward therefore
belongs to that person.
Do not send these calls together with `Promise.all()`. The event could reach
Quotient before the person has been identified, causing it to be recorded as an
event that is not linked to a known person.
If the visitor has already been identified by a tagged email link or an earlier
`identify()` call, you only need to send the custom event.
## What Quotient Records
The SDK adds context automatically. In addition to the custom event ID, Quotient
records the current page, browsing session, and attribution from the visitor's
`utm_*` and `qt_*` URL parameters. When the browser knows the person, their
Quotient person ID is included too.
An event can still be useful when Quotient does not know the visitor's identity.
Quotient can attribute it to the campaign, email, social post, and session that
brought the visitor to your site, even when it cannot name the person.
Custom events do not currently accept additional event properties. Do not add
form fields, email addresses, or other personal information to the analytics
call. Store person information with `people.identify()` instead.
## Test Your Event
Test from a domain included in your public API key's allowed origins:
1. Open your browser's developer tools and select **Network**.
2. Complete the action that should send the event.
3. Search the requests for `analytics/web`.
4. Select the request and confirm that its status is `200`.
A `422` response usually means the `customEventId` does not exactly match an
event registered in Quotient. Event IDs are case-sensitive. A `403` response
usually means the site's domain is missing from the API key's allowed origins,
or the key does not have **Analytics: write** permission.
Once the request succeeds, ask Quotient a question such as:
> How many Requested Demo events did we record in the last 30 days, broken down
> by UTM source?
## Tips for Useful Events
- Track completed outcomes instead of button clicks or attempted submissions.
- Use one stable event ID for the same action across your site.
- Avoid sending the same event from more than one handler, which would count one
action twice.
- Upsert the person first when the same form also adds them to Quotient.
## Next Steps
-- End of: /analytics/custom-events/index
-- Start of: /analytics/custom-events/server-side-conversions
---
title: Server-Side Conversions
description:
Connect the conversions your server records to the marketing that brought the
visitor to your site
order: 1
---
Some conversions never happen in the browser. An OAuth callback creates the
account, a payment provider's webhook confirms the purchase, a background job
marks the trial as started. Your server knows the conversion happened, but the
marketing that caused it was only ever visible in the visitor's browser: the
newsletter link they clicked, the campaign in the URL, the session they were in.
This guide shows how to carry that browser-side knowledge to your server, so a
server-recorded event is attributed the same way a browser event would be.
Before you begin:
- [Install Quotient website tracking](/docs/analytics/on-site-tracking/custom-website) on your
site. The browser SDK is what collects the attribution in the first place.
- Install `@quotientjs/server` and create a private API key with
**Analytics: write** permission. See the
[server analytics API](/docs/sdk/analytics#track-a-server-event) for the
event call itself.
- [Create the custom event](/docs/analytics/custom-events) in Quotient. Server
events use the same registered event IDs as browser events.
## How the Browser Hands Off What It Knows
The browser SDK keeps a small record of the current visitor: which device and
session they are in, who they are if a tagged link or `people.upsert()` has
identified them, the page that referred them, and the `utm_*` and `qt_*`
attribution from the URL they arrived on. Quotient calls this record the
**browser context**. It reaches your server in one of two ways.
**The `qt_browser_context` cookie.** On every tracked event, the SDK writes the
browser context to a first-party cookie named `qt_browser_context`. The browser
attaches it to every request to your own domain, including requests that no page
of yours sends, such as an OAuth callback. Read it when the request that
completes the conversion is a request to your own domain.
The cookie expires 30 minutes after the visitor's last tracked event, the same
lifetime as the analytics session. If the cookie is present, the session it
describes is still live.
**`client.getBrowserContext()`.** Cookies do not travel to other domains. When
your conversion request goes to an API on a different domain, ask the browser
SDK for the same record and send it in your request body:
```typescript
const browserContext = client.getBrowserContext();
await fetch("https://api.yourcompany.com/signup", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ ...formData, browserContext }),
});
```
## What the Browser Context Contains
Both paths give you the same object:
```typescript
type BrowserContext = {
version: 1;
deviceId?: string; // random ID minted the first time this browser loaded the SDK
sessionId: string; // the rolling 30-minute session
personId?: string; // set once a tagged link or people.upsert() identified the visitor
referrerUrl?: string; // the external page that sent the visitor
attribution: Attribution; // utm_* and qt_* parameters from the arrival URL; {} when untagged
};
```
The cookie value is `encodeURIComponent(JSON.stringify(browserContext))`.
This shape is a stable contract. Fields are only ever added while `version`
stays `1`, so it is safe to store the object or forward it through your own
systems. If your code sees a `version` it does not recognize, ignore the object
rather than guessing at its contents.
## Record the Event on Your Server
Read the cookie (or the body field), parse it, and pass the result as
`browserContext` on the server event. Quotient then stores the event with the
same session, device, referrer, and attribution a browser event would carry, so
the source, campaign, and content dimensions in your reports include it.
```typescript
import {
BROWSER_CONTEXT_COOKIE_NAME,
type BrowserContext,
} from "@quotientjs/server";
// The cookie is untrusted input. Treat anything unreadable as "no context"
// so a bad cookie can never break your own signup handler.
function readBrowserContext(
cookieValue: string | undefined,
): BrowserContext | undefined {
if (!cookieValue) return undefined;
try {
return JSON.parse(decodeURIComponent(cookieValue));
} catch {
return undefined;
}
}
// inside your signup handler, after the account is actually created
// (Next.js shown; `cookies.get()` returns an object with a `value`)
const browserContext = readBrowserContext(
request.cookies.get(BROWSER_CONTEXT_COOKIE_NAME)?.value,
);
await quotient.analytics.event({
eventType: "custom",
personId: person.id,
customEventId: "signedUp",
browserContext,
});
```
Send the event after the conversion has actually succeeded, the same rule as for
browser events. If the account was not created, there is nothing to attribute.
## What Quotient Trusts
The browser context is a claim about attribution, and only that. It comes from
the visitor's browser, so Quotient never lets it decide who an event belongs to:
- `personId` on the event itself decides the person. `browserContext.personId`
is ignored, and the API still checks that `personId` belongs to your business.
- A `browserContext` the API cannot make sense of (an unknown `version`, or
attribution that breaks the URL-tagging rules) is dropped, and the event is
recorded without attribution. A stale or tampered cookie never costs you the
conversion itself.
## Next Steps
-- End of: /analytics/custom-events/server-side-conversions
-- Start of: /analytics/on-site-tracking/custom-website
---
title: Custom Website
description: Install website tracking on a site you build and host yourself
order: 1
---
When someone reaches your website from a Quotient email, social post, or
campaign, the Quotient pixel shows you what they do next. It records the pages
they visit while preserving the content that brought them to your site as the
source.
This guide covers websites that you build yourself, from static HTML hosted on
GitHub Pages to applications built with React, Next.js, Remix, or React Router.
If you use a hosted website builder, follow the instructions for that platform
instead.
## Create a Public API Key
Create a key in
[Settings → Developers](/s/most-recent-business/settings/developers). Choose a
**Public** key and give it the **Analytics: write** permission.
Add every domain where you will run the pixel to the key's allowed origins. For
example, you might add:
- `https://example.com` for your production site
- `https://your-name.github.io` for a GitHub Pages site
- `http://localhost:3000` for local development
Each origin must match exactly, including `https://`. If your site loads on both
`https://example.com` and `https://www.example.com`, add both.
Allowed origins prevent another website from using your key. The key you copy
should begin with `pk_`. Never put a private key beginning with `sk_` in code
that runs in a browser.
## Choose an Installation Method
The right installation method depends on how your site is built.
### Static HTML
Use this method for a site made from HTML files, including a static site hosted
on GitHub Pages. Add the following code before the closing `