> ## Documentation Index
> Fetch the complete documentation index at: https://docs.permutive.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Planning a custom audience for a campaign brief

> Respond to a campaign brief with an audience accurately matching the targeting requirements, and generate insights to support your response.

export const RailStep = ({step, title, note = '', docLink = '', docPages = '', docTitle = 'From the brief — highlighted for this page', docWide = false}) => <li className={step === '1' ? 'agent-chat-rail-step is-active' : 'agent-chat-rail-step'} data-step={step}>
    <a className="agent-chat-note-title" href={`#step-${step}`}>{title}</a>
    <div className="agent-chat-note-body">
      <div>
        {note.split('`').map((part, i) => i % 2 === 1 ? <a key={i} href={`/api/mcp/${part}`}><code>{part}</code></a> : <span key={i}>{part}</span>)}
        {docLink && <button type="button" className="agent-chat-doc-link" popovertarget={`doc-step-${step}`}>
            {docLink} →
          </button>}
      </div>
    </div>
    {docLink && <div id={`doc-step-${step}`} popover="auto" className={docWide ? 'agent-chat-document agent-chat-document-annotated agent-chat-document-wide' : 'agent-chat-document agent-chat-document-annotated'}>
        <div className="agent-chat-document-header">
          <span>{docTitle}</span>
          <button type="button" popovertarget={`doc-step-${step}`} popovertargetaction="hide" aria-label="Close">✕</button>
        </div>
        <div className="agent-chat-document-pages">
          {docPages.split(';').map(src => src.trim()).filter(Boolean).map((src, i) => <img key={src} src={src} alt={`${docTitle}, part ${i + 1}`} noZoom />)}
        </div>
      </div>}
  </li>;

export const StepRail = ({children}) => <aside className="agent-chat-rail" aria-label="Steps">
    <ol className="agent-chat-rail-list">{children}</ol>
  </aside>;

export const AnnotatedTurn = ({step, title, children}) => <section id={`step-${step}`} className="agent-chat-turn" data-turn-step={step}>
    <div className="agent-chat-turn-label">{step}. {title}</div>
    {children}
  </section>;

export const AnnotatedConversation = ({children}) => <div className="agent-chat-conversation">{children}</div>;

export const BarChart = ({title, unit = 'Unique users', data = ''}) => {
  const rows = data.split(';').map(pair => pair.trim()).filter(Boolean).map(pair => {
    const [label, value] = pair.split('=');
    return {
      label: label.trim(),
      value: Number(value)
    };
  });
  const max = Math.max(...rows.map(d => d.value));
  return <div className="agent-chat-chart" role="img" aria-label={title}>
      <div className="agent-chat-chart-caption">
        <div className="agent-chat-chart-title">{title}</div>
        <div className="agent-chat-chart-unit">{unit}</div>
      </div>
      {rows.map(d => <div key={d.label} className="agent-chat-chart-row">
          <span className="agent-chat-chart-label">{d.label}</span>
          <span className="agent-chat-chart-track">
            <span className="agent-chat-chart-bar" style={{
    width: `${d.value / max * 100}%`
  }} />
          </span>
          <span className="agent-chat-chart-value">{d.value.toLocaleString('en-US')}</span>
        </div>)}
    </div>;
};

export const ResponseFull = ({children}) => <details className="agent-chat-full">
    <summary></summary>
    <div className="agent-chat-full-body">{children}</div>
  </details>;

export const ResponseExcerpt = ({children}) => <div className="agent-chat-excerpt">{children}</div>;

export const AgentResponse = ({tools = '', skill = '', children}) => <div className="agent-chat-agent">
    {skill && <div className="agent-chat-tools">
        Using skill: <code>{skill}</code>
      </div>}
    {tools && <div className="agent-chat-tools">
        Used Permutive MCP
        {tools.split(',').map(t => t.trim()).filter(Boolean).map((tool, i) => <span key={tool}>
            {i === 0 ? ': ' : ', '}
            <a href={`/api/mcp/${tool}`}><code>{tool}</code></a>
          </span>)}
      </div>}
    <div className="agent-chat-body">{children}</div>
  </div>;

export const UserPrompt = ({children}) => <div className="agent-chat-user">
    <div className="agent-chat-user-bubble">{children}</div>
  </div>;

<Note>
  The Permutive MCP server is in a **testing phase with partnering customers**.
  Access is invitation-only and the tool interfaces may change. If you would like
  access, please contact your Permutive representative.
</Note>

## Scenario

A brief lands with your ad-ops or sales team.

Normally, you would spend a lot of time researching suitable cohorts, analyzing combinations of them,
and creating insights to share with the customer, creating graphs offline in a spreadsheet.

## How the Permutive MCP server powers the agent

With the Permutive MCP server, your agent is able to automate this by:

* **Find suitable cohorts** — our advanced semantic search surfaces
  cohorts without requiring direct keyword matches, and can intelligently
  find ones you may not have thought to look for
* **Combine and measure audiences to fit the brief** — the agent can iterate through
  many different combinations of cohorts to find the best fit based on reach,
  engagement, platform, property and other factors
* **Explain and illustrate the audience** — understand the make-up of your
  audience by property, platform, engagement, and the interests it over-indexes
  on, ready to drop into your response

## Example conversation

<AnnotatedConversation>
  <StepRail>
    <RailStep step="1" title="Describe the brief" note="Start with the key details from the brief, asking for output in a way that is easy to scan." />

    <RailStep step="2" title="The agent finds candidate cohorts" note="The agent picks the US workspace, then uses `search_cohorts` and `list_cohorts` to group cohorts by the job they'd do." />

    <RailStep step="3" title="The agent can recommend without keyword matching" note="The agent flags that there is no specific running cohort, but our intelligent semantic search allowed the " />

    <RailStep step="4" title="Set a reach target" note="Give the number the brief needs. Asking for three options lets you compare different trade-offs rather than accept the first answer." />

    <RailStep step="5" title="The agent builds and sizes audiences" note="The agent iterates with `measure_audiences`, sizing each combination on de-duplicated US users. It flags what it couldn't do: a strict affluence filter can't reach 1M." />

    <RailStep step="6" title="Ask for the evidence" note="Pick an audience and say exactly what your response needs: here, breakdowns, a persona, and charts." />

    <RailStep step="7" title="The agent charts and profiles the audience" note="Domain and device breakdowns come from `measure_audiences` and are drawn as charts. The persona is written from the behavior behind the cohorts, with caveats on what's modeled." />
  </StepRail>

  <AnnotatedTurn step="1" title="Describe the brief">
    <UserPrompt>
      I need to build an audience for a campaign a sportswear brand wants to run —
      they're launching new high-end running shoes in the US market.

      Let's work step by step. What cohorts do we have that might be suitable? Group
      by role and output as tables.
    </UserPrompt>
  </AnnotatedTurn>

  <AnnotatedTurn step="2" title="The agent finds candidate cohorts">
    <AgentResponse tools="get_orgs_and_workspaces, get_workspace_details, search_cohorts, list_cohorts">
      <ResponseExcerpt>
        I'll work in **Quorrane Media US** (16.8M US users) plus
        the parent workspace, which holds the demographic and income library.

        Full catalogue reviewed — 124 enabled cohorts across **Quorrane Media US** and the
        parent workspace. Here's what's usable, grouped by the job each would do in the build.

        **1. Core activity signal — the "runner" proxy**

        | Cohort | ID | Users | Variant logic |
        | - | - | - | - |
        | Health & Wellness — regular readers (7d) | `ftex` | 4.19M | 3+ sessions in 7d |
        | Health & Wellness — frequent visitors | `feqh` | 3.18M | 4+ sessions/week |
        | Health & Wellness — high-intent (30d) | `diik` | 2.10M | Sessions ending on transactional/comparison pages |
        | Health & Wellness — enthusiasts | `xchr` | 1.67M | 10+ articles, multi-subtopic, 3mo |
        | Health & Wellness — newly engaged (90d) | `480788` | 1.49M | First session in last 90d |
        | Health & Wellness — recent buyers (90d) | `jtdy` | 1.07M | Trail ending on order confirmation |
      </ResponseExcerpt>

      <ResponseFull>
        Workspaces confirmed — I'll work in **Quorrane Media US** (16.8M US users) plus
        the parent workspace, which holds the demographic and income library.

        Full catalogue reviewed — 124 enabled cohorts across **Quorrane Media US** and the
        parent workspace. Here's what's usable, grouped by the job each would do in the build.

        All figures are 30-day unique users at workspace level, and include Canada and Mexico (\~20% of reach) — US-only targeting will pull these down.

        **1. Core activity signal — the "runner" proxy**

        | Cohort | ID | Users | Variant logic |
        | - | - | - | - |
        | Health & Wellness — regular readers (7d) | `ftex` | 4.19M | 3+ sessions in 7d |
        | Health & Wellness — frequent visitors | `feqh` | 3.18M | 4+ sessions/week |
        | Health & Wellness — high-intent (30d) | `diik` | 2.10M | Sessions ending on transactional/comparison pages |
        | Health & Wellness — enthusiasts | `xchr` | 1.67M | 10+ articles, multi-subtopic, 3mo |
        | Health & Wellness — newly engaged (90d) | `480788` | 1.49M | First session in last 90d |
        | Health & Wellness — recent buyers (90d) | `jtdy` | 1.07M | Trail ending on order confirmation |

        **2. Sports affinity — category context**

        | Cohort | ID | Users | Variant logic |
        | - | - | - | - |
        | Sports Fans — regular readers (7d) | `jumi` | 7.25M | 3+ sessions in 7d |
        | Sports Fans — frequent visitors | `rlzh` | 5.43M | 4+ sessions/week |
        | Sports Fans — enthusiasts | `946476` | 2.91M | 10+ articles, multi-subtopic, 3mo |
        | Sports Fans — newly engaged (90d) | `ffzh` | 2.53M | First session in last 90d |

        This family has only four variants — there is no Sports Fans high-intent or recent-buyers cohort.

        **3. Purchase intent — retail behaviour**

        | Cohort | ID | Users | Variant logic |
        | - | - | - | - |
        | Frequent Shoppers — regular readers (7d) | `tqof` | 6.18M | 3+ sessions in 7d |
        | Frequent Shoppers — frequent visitors | `ndwi` | 4.62M | 4+ sessions/week |
        | Frequent Shoppers — high-intent (30d) | `977544` | 3.09M | Sessions ending on transactional/comparison pages |
        | Frequent Shoppers — enthusiasts | `hdab` | 2.48M | 10+ articles, multi-subtopic, 3mo |
        | Frequent Shoppers — newly engaged (90d) | `fwcx` | 2.18M | First session in last 90d |
        | Frequent Shoppers — recent buyers (90d) | `rnuj` | 1.57M | Trail ending on order confirmation |

        **4. Premium qualifier — the "high-end" filter**

        | Cohort | ID | Users | Basis |
        | - | - | - | - |
        | Household income \$100k+ | `294546` | 8.93M | Modelled |
        | Household income \$200k+ | `dmen` | 2.81M | Modelled |
        | Luxury Lifestyle — regular readers (7d) | `hqvp` | 387k | Observed |
        | Luxury Lifestyle — frequent visitors | `dyxr` | 279k | Observed |
        | Luxury Lifestyle — high-intent (30d) | `611350` | 195k | Observed |
        | Luxury Lifestyle — enthusiasts | `tgrq` | 139k | Observed |
        | Luxury Lifestyle — newly engaged (90d) | `pkvo` | 118k | Observed |
        | Luxury Lifestyle — recent buyers (90d) | `hpqp` | 82k | Observed |

        **5. Demographic framing**

        | Cohort | ID | Users |
        | - | - | - |
        | Adults 25–34 | `967292` | 8.96M |
        | Adults 35–44 | `rqfu` | 8.55M |
        | Adults 45–54 | `786934` | 7.48M |
        | Adults 18–24 | `926978` | 5.99M |
        | Young professionals | `fisp` | 7.87M |
        | College educated | `ltyq` | 13.03M |
        | Male / Female | `945818` / `978696` | 24.5M / 24.6M |

        **6. Style adjacency and suppression candidates**

        | Cohort | ID | Users | Role |
        | - | - | - | - |
        | Fashion & Beauty — regular readers (7d) | `dwjo` | 5.19M | Sneaker-as-style reach extension |
        | Fashion & Beauty — high-intent (30d) | `lffw` | 2.59M | Style-led purchase intent |
        | Fashion & Beauty — enthusiasts | `293340` | 2.15M | Style-led precision |
        | Household income under \$50k | `vfvo` | 13.96M | Suppress for high-end pricing |
        | Retirees | `500896` | 7.22M | Suppress if brief skews younger |
        | Adults 55+ | `bppe` | 10.98M | Suppress or hold separate |
      </ResponseFull>
    </AgentResponse>
  </AnnotatedTurn>

  <AnnotatedTurn step="3" title="The agent flags gaps and recommends">
    <AgentResponse>
      Three things to flag before we build:

      * **There is no running, footwear, or athletic-apparel cohort in the catalogue**, and no brand-affinity cohort for the advertiser or its competitors. Health & Wellness (fitness, nutrition, wellbeing content) is the closest behavioural proxy we have, so "runner" will be inferred rather than observed.
      * Income and age are modelled attributes, not observed behaviour. If the brief needs an affluence guarantee, Luxury Lifestyle is observed but very small — 82k to 387k.
      * Purchase intent has to come from Frequent Shoppers, since the Sports Fans family has no high-intent variant.

      **My recommendation is to build two: a precision audience on Health & Wellness enthusiasts AND high-intent shoppers AND \$100k+, and a reach audience on Sports Fans OR Health & Wellness with the under-\$50k suppression only**. Do you have a minimum deliverable from the brand I should size against, or shall I build both and let the numbers set the shape?
    </AgentResponse>
  </AnnotatedTurn>

  <AnnotatedTurn step="4" title="Set a reach target">
    <UserPrompt>
      My target is around 1 million uniques.

      Suggest 3 relevant audiences that would have that reach.
    </UserPrompt>
  </AnnotatedTurn>

  <AnnotatedTurn step="5" title="The agent builds and sizes audiences">
    <AgentResponse tools="measure_audiences">
      <ResponseExcerpt>
        All three clear your 1M target. Measured over the last 30 days, US traffic only, in **Quorrane Media US**.

        **Audience 1: Premium fitness core**

        Committed fitness and wellbeing readers with real content depth, screened against the value-shopping end of the market.

        * **Reach** — 1,226,000 users
        * **Inventory** — 6,620,000 page views (30 days)
        * **Against the brief** — clears the 1,000,000 minimum by 23%
        * **Targeted Cohorts** — Users in Health & Wellness — enthusiasts NOT Household income under \$50k
      </ResponseExcerpt>

      <ResponseFull>
        All three clear your 1M target. Measured over the last 30 days, US traffic only, in **Quorrane Media US**.

        **Audience 1: Premium fitness core**

        Committed fitness and wellbeing readers with real content depth, screened against the value-shopping end of the market.

        * **Reach** — 1,226,000 users
        * **Inventory** — 6,620,000 page views (30 days)
        * **Against the brief** — clears the 1,000,000 minimum by 23%
        * **Targeted Cohorts** — Users in Health & Wellness — enthusiasts NOT Household income under \$50k

        **Audience 2: Sport-and-fitness regulars**

        Habitual visitors who follow both training content and competitive sport, the closest behavioural stand-in we have for an active runner.

        * **Reach** — 1,052,500 users
        * **Inventory** — 5,683,500 page views (30 days)
        * **Against the brief** — clears the 1,000,000 minimum by 5%
        * **Targeted Cohorts** — Users in (Health & Wellness — frequent visitors AND Sports Fans — regular readers (7d)) NOT Household income under \$50k

        **Audience 3: Proven fitness buyers**

        People who have actually completed a purchase off wellbeing content, plus fitness shoppers who also read sport in depth.

        * **Reach** — 1,100,500 users
        * **Inventory** — 5,942,700 page views (30 days)
        * **Against the brief** — clears the 1,000,000 minimum by 10%
        * **Targeted Cohorts** — Users in (Health & Wellness — recent buyers (90d) OR (Health & Wellness — high-intent (30d) AND Sports Fans — enthusiasts)) NOT Household income under \$50k

        Three things to catch before this goes to the brand:

        * The high-end positioning is carried by suppression, not by a positive affluence signal. Holding \$100k+ in the build collapses reach to 58,000–100,000, and a three-way AND with shopper intent lands at 1,000 users, so it cannot survive at this scale.
        * The under-\$50k suppression only removes about 9% of Audience 1, and it is a modelled exclusion rather than observed behaviour — worth deciding whether it earns its place in the response.
        * All three share a Health & Wellness spine, so they are not additive. Running all three will not deliver 3.4M uniques.

        Want me to pull the evidence — cohort contributions, domain and device splits, and overlap between the three — or refine the builds first?
      </ResponseFull>
    </AgentResponse>
  </AnnotatedTurn>

  <AnnotatedTurn step="6" title="Ask for the evidence">
    <UserPrompt>
      Let's go with that first audience. I need the following to put in my response to
      the customer:

      * Breakdowns by property and platform
      * The audience as a persona

      Use charts for the breakdowns.
    </UserPrompt>
  </AnnotatedTurn>

  <AnnotatedTurn step="7" title="The agent charts and profiles the audience">
    <AgentResponse tools="measure_audiences">
      <ResponseExcerpt>
        Audience 1 measured with breakdowns — 1,226,000 US users, 6,620,400 page views over the last 30 days.

        **By property**

        <BarChart title="Premium fitness core — unique users by property (US, 30 days)" data="northernherald.com=383000; metrochronicle.com=242000; beaconwire.com=183000; summitfinance.com=117000; ledgerreport.com=98250; starlinemedia.com=95250; midfielddigest.com=58000; openforum.net=49500" />

        **By platform**

        <BarChart title="Premium fitness core — unique users by platform (US, 30 days)" data="Mobile=724750; Desktop=371000; Tablet=130250" />

        **The persona**

        > **The committed wellbeing reader.** She is a sustained, self-directed reader of fitness, nutrition and mental-wellbeing content — not someone who dips in for a New Year resolution piece, but someone who has worked through ten or more articles across several sub-topics over the past three months. Training, recovery, food and mindset all hold her attention. She reads mostly on her phone, in short focused sessions, and returns often enough to generate five or six page views a month across our titles. She reads general news and, notably, personal finance alongside her wellbeing habit, which places her in a household with discretionary spend rather than a value-seeking one. She is the reader who researches before she buys, and who treats a premium running shoe as equipment worth getting right rather than an impulse purchase.
      </ResponseExcerpt>

      <ResponseFull>
        Audience 1 measured with breakdowns — 1,226,000 US users, 6,620,400 page views over the last 30 days.

        **By property**

        <BarChart title="Premium fitness core — unique users by property (US, 30 days)" data="northernherald.com=383000; metrochronicle.com=242000; beaconwire.com=183000; summitfinance.com=117000; ledgerreport.com=98250; starlinemedia.com=95250; midfielddigest.com=58000; openforum.net=49500" />

        Delivery concentrates on three properties — northernherald.com, metrochronicle.com and beaconwire.com together carry 66% of the audience. The two finance titles, summitfinance.com and ledgerreport.com, contribute a further 17.5%, which is useful supporting colour for the premium read since it is observed behaviour rather than a modelled income attribute.

        **By platform**

        <BarChart title="Premium fitness core — unique users by platform (US, 30 days)" data="Mobile=724750; Desktop=371000; Tablet=130250" />

        Mobile takes 59% of the audience, desktop 30%, tablet 11%. Creative should be built mobile-first. Engagement runs at 5.4 page views and 45 seconds of engaged time per user.

        **The persona**

        > **The committed wellbeing reader.** She is a sustained, self-directed reader of fitness, nutrition and mental-wellbeing content — not someone who dips in for a New Year resolution piece, but someone who has worked through ten or more articles across several sub-topics over the past three months. Training, recovery, food and mindset all hold her attention. She reads mostly on her phone, in short focused sessions, and returns often enough to generate five or six page views a month across our titles. She reads general news and, notably, personal finance alongside her wellbeing habit, which places her in a household with discretionary spend rather than a value-seeking one. She is the reader who researches before she buys, and who treats a premium running shoe as equipment worth getting right rather than an impulse purchase.

        Two caveats to keep visible in the response: the persona's affluence rests on a modelled income exclusion plus the finance-title readership above, not on a declared income signal; and "runner" is inferred from fitness content depth, since we hold no running or footwear cohort.

        Want me to also pull the day-by-day trend, or extrapolate the 30-day inventory to the brand's flight length?
      </ResponseFull>
    </AgentResponse>
  </AnnotatedTurn>
</AnnotatedConversation>

## Tips

* **Work step by step**: You can ask for everything in one prompt, but working
  through each stage lets you drop a cohort, change the target, or try another
  market before the agent moves on.
* **Say what the output is for**: "For an RFP response" or "for a client deck"
  shapes how the agent presents results. Ask for tables and charts explicitly.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.