Skip to content

Integration  ·  Marketing

How to build an ad audience sync

A customer sees an advert asking them to try the product they already pay for. The thinking behind audiences that know better, the prompts that build it, and what it takes to keep it running.

Built with Tray Headless

  1. System Salesforce
  2. Step Build from CRM state
  3. Step Suppress
  4. Step Hash locally
  5. System LinkedIn Ads
Also Snowflake

Suppression is applied before the audience leaves, and identifiers are hashed locally so raw email never reaches the platform.

The short answer

What is an ad audience sync?

Done well, an ad audience sync is four things: audiences built from live CRM state rather than an exported list, suppression applied before anything leaves so customers and open deals are never targeted, identifiers hashed locally so raw email never reaches the platform, and a refresh cadence fast enough that the audience is not stale. The part that goes wrong most often is suppression. Advertising acquisition to an existing customer wastes the spend and tells them your systems do not talk to each other.

What matters here

  • Never upload an exported list. It is stale the moment it is downloaded and it cannot be suppressed.
  • Suppress customers, open opportunities, recent churns and anybody who opted out, before the audience leaves your systems.
  • Hash identifiers locally. Raw email should never reach an ad platform, and hashing at the boundary is the cheapest privacy control there is.
  • Refresh at least daily. An audience refreshed monthly is advertising to people whose situation changed three weeks ago.
  • Track match rate per platform. A low match rate means you are paying for reach you are not getting.

Who this is for

You run marketing operations or demand generation. Audiences are exported to CSV, uploaded by hand, and nobody is quite sure whether current customers are in them.

How it works in practice

The sequence, from a segment being defined to an advert being served.

  1. 1

    The audience is defined as CRM state, not a list

    A saved query evaluated at run time, so somebody who converted this morning leaves it today.

  2. 2

    Suppression runs before anything leaves

    Existing customers, open opportunities, recent churns, opt-outs and competitor domains.

  3. 3

    Identifiers are hashed locally

    Normalised then hashed before transmission, so raw email never reaches the platform.

  4. 4

    The audience is synced as a delta

    Adds and removes, rather than replacing the whole list and resetting the platform learning.

  5. 5

    Match rate is recorded per platform

    Because you are paying for reach and a poor match means you are not getting it.

  6. 6

    Suppression is re-evaluated on every refresh

    A customer who signed yesterday leaves the acquisition audience today, not next month.

What audience sync is made of

Four parts, though the second is the one customers notice when it is missing.

Live CRM state

A query evaluated at run time. An exported list is a snapshot of a moment that has already passed.

Suppression before sending

Customers, open deals, churns, opt-outs and competitors, applied inside your systems instead of hoped for at the platform.

Local hashing

Normalise and hash at the boundary. The platform gets a hash, never an address, and that is the cheapest privacy control available.

Delta refresh

Adds and removes rather than a full replace, so platform optimisation is not reset every night.

The Tray Headless prompts

Paste these into Claude Code or Codex with the Tray Headless plugin installed. Each stage runs on its own. The systems named in them are the worked example rather than a requirement, and every prompt says so.

Once per project, run /tray-workflows:set-workspace to pick the workspace these build in. Point it at a sandbox first.

  1. 1

    Start here: define suppression first

    Suppression is the reason to build this instead of exporting a CSV.

    Headless skills build-workflow

    Use build-workflow. The systems in play are Salesforce and the ad
    platforms we run, or whatever we run in those seats.
    
    Before defining any audience, define the suppression list:
    
      Anybody at an account with an active subscription
      Anybody at an account with an open opportunity above a stage
      Anybody who churned in the last year, which is a win-back audience
      instead of an acquisition one
      Anybody who opted out of marketing
      Employees, competitors and partners by domain
    
    Tell me where each of those lives. Suppression is the reason to build
    this instead of exporting a spreadsheet, so it gets designed first.
  2. 2

    Build audiences from live state, never a list

    An exported list is stale before it finishes downloading.

    Headless skills build-workflow

    Use build-workflow. Define each audience as a saved query against the CRM
    and the warehouse, evaluated at run time.
    
    Never accept a static uploaded list. Somebody who converted this morning
    should leave the acquisition audience today, and a list cannot do that.
    
    Apply suppression after building the audience and before anything leaves
    our systems. Do not rely on the platform to exclude a list you also
    uploaded, because the exclusion rules differ per platform and the failure
    mode is invisible.
    
    Log the suppression counts per run. If suppression removes a large share
    of an audience, the audience definition is wrong rather than suppression
    working hard.
  3. 3

    Hash before it leaves

    The cheapest privacy control available.

    Normalise then hash every identifier before transmission: lowercase and
    trim the email, strip plus-addressing, normalise phone numbers to E.164,
    then hash with the algorithm each platform specifies.
    
    Raw email addresses should never reach an ad platform. Hashing at the
    boundary costs nothing and removes an entire category of problem from
    your data processing agreements.
    
    Send the minimum each platform needs for matching. Do not send company,
    job title or anything else because a field happened to be available.
  4. 4

    Sync deltas and keep the audience alive

    A full replace resets platform learning every night.

    Headless skills tray-gotchas

    Use tray-gotchas, then sync as a delta: adds and removes against what the
    platform already holds, rather than replacing the audience wholesale.
    
    A full replace resets the platform's optimisation and it shows in
    performance within days.
    
    Refresh at least daily. Handle these:
    
      An audience that falls below the platform minimum size, which silently
      stops serving rather than erroring
      A platform rejecting a batch, which must not leave the audience half
      updated
      Removals failing, which is the dangerous direction because it means a
      customer is still being targeted
      An audience that has not refreshed within its window, which should
      alert rather than quietly go stale
  5. 5

    Measure match rate and suppression

    Because you are paying for reach you may not be getting.

    Report per audience and per platform: size, match rate, suppression
    counts by reason, and how long since the last successful refresh.
    
    Match rate is the number that matters commercially. A 40% match means
    more than half the audience is not reachable and the spend is
    concentrating on whoever did match, which is rarely the segment you
    designed.
    
    Alert on: match rate dropping sharply, an audience below the minimum
    serving size, a refresh that has not completed, and any run where
    suppression removed nothing, because that usually means the suppression
    join silently broke.
  6. 6

    Check it end to end, then hand the definitions over

    Because audiences change with every campaign.

    Run the per-step schema checks and the whole-workflow audit before this
    touches production. Run once in preview, showing the audience and the
    suppression counts without sending, and have somebody read it.
    
    Then open the same workflow in Tray Build so marketing operations can
    define new audiences and amend suppression rules in the visual canvas.

What it connects to

The CRM decides who, the warehouse adds context, and the platforms receive hashes.

Salesforce

Read accounts, contacts, opportunities and opt-out state, which is what both the audience and the suppression are built from.

Reads

Snowflake

Add product usage and segmentation the CRM does not hold, and record match rates over time.

Reads and writes

LinkedIn Ads

Sync the hashed audience as a delta, and read back the match rate.

Reads and writes

Google Ads

The same, with its own hashing requirements and minimum audience size.

Reads and writes

Marketo

Read engagement, so a retargeting audience can exclude people already in an active nurture.

Reads

Slack

Alert on a stale audience, a collapsed match rate or a suppression join that removed nothing.

Writes

Same build, other stacks

The design does not change if you run something else in one of these seats. The same prompts build it against Microsoft Dynamics 365, Google BigQuery, Microsoft Teams, HubSpot, Databricks or Google Chat.

Named systems are the ones most teams run, not the only ones that work. Each is an authentication in your Tray workspace, referenced by name, so the workflow never holds a credential. Where we have a connector page, the name links to it.

Running it in production

This sends customer identifiers to third parties and spends money. Both need care.

It lives on the platform, not in a terminal window

Daily rebuilds with suppression re-evaluated each time run on the same engine, instead of a person exporting a CSV when they remember.

Every send is recorded

Which audience, how many, what suppression removed, and the match rate returned. That record is what a privacy review asks for.

Credentials are managed, never written into the build

Ad platform credentials can spend money and upload customer data. They live in your workspace, scoped per platform and separately revocable.

Marketing owns the definitions

Audience queries and suppression rules open in Tray Build, so a new campaign does not need an engineer.

Hashing happens before the boundary

Raw identifiers never leave your systems. It costs nothing and removes a whole category of problem from the data processing agreement.

Questions people ask

Why not upload an exported list?

Because it is stale the moment it downloads and it cannot be suppressed. Somebody who becomes a customer that morning stays in the acquisition audience until the next manual upload.

Why suppress inside your own systems?

Because platform exclusion rules differ and fail silently. Applying suppression before the audience leaves means a customer cannot be targeted even if a platform setting is wrong.

Why hash locally?

Because raw email should never reach an ad platform. Normalising and hashing at the boundary costs nothing and removes an entire category of question from a privacy review.

Why sync deltas rather than replacing?

Because a full replace resets the platform optimisation, and the performance drop shows within days. Adds and removes keep the audience learning intact.

What should be monitored?

Match rate per platform, and any run where suppression removed nothing. A low match rate means you are paying for reach you are not getting, and zero suppression usually means a join broke.

Further reading

Background on the same subject, for the case rather than the build.

Last reviewed September 2026.