Skip to content
adscapi

Audiences

Upload a hashed customer list to one platform's Customer Match / Custom Audience API. 28 destinations. Emails go in raw — the SDK SHA-256 hashes them. A platform without secrets is skipped, not errored.

Signature

ts
import { createAdscapi } from 'adscapi';

const ads = createAdscapi();

// Platforms that support audience upload
const platforms = ads.audiences.list();
// → readonly AudiencePlatform[]
//   'google' | 'meta' | 'bing' | 'tiktok' | 'linkedin' | …

// Upload one list to one platform. Secrets come from the client — omit them here.
const result = await ads.audiences.sync({
  platform: 'meta',
  listName: 'high-value-buyers',
  emails: ['jane@example.com', 'bob@acme.com'], // raw — SDK hashes
  consent: { adUserData: true, adPersonalization: true },
});

audiences.sync(opts)

On the client, secrets is injected for you — pass everything else:

FieldTypeNotes
platformAudiencePlatformOne of the keys returned by audiences.list()
listNamestringAudience / list display name on the platform
emailsstring[]Raw addresses. Normalized + SHA-256 hashed inside syncAudience. Never pre-hash
consent{ adUserData: boolean; adPersonalization: boolean }Required consent flags for the upload

Return — SyncAudienceResult

ts
type SyncAudienceResult =
  | { platform: string; audienceId: string; verifiedSize: number }
  | { platform: string; skipped: true; reason: string };

// skipped reasons include:
//   'unknown platform'
//   'platform is not configured'

Flow per platform: begin → chunked ingest (≤10,000 members per chunk) → verifySize.

audiences.list()

ts
ads.audiences.list(): readonly AudiencePlatform[]

// Currently:
// google, meta, bing, tiktok, linkedin, reddit, pinterest, snapchat, x,
// yandex, vk, tencent, baidu, douyin, kuaishou, naver, kakao, line,
// yahoojp, mercadolibre, amazon, criteo, taboola, outbrain, tradedesk,
// stackadapt, quora, nextdoor

Example

ts
import { createAdscapi, audienceFromConversions } from 'adscapi';

const ads = createAdscapi();

// Option A — hand a raw email list
const result = await ads.audiences.sync({
  platform: 'google',
  listName: 'newsletter-subscribers-2026-q1',
  emails: subscribers.map((s) => s.email),
  consent: { adUserData: true, adPersonalization: true },
});

if ('skipped' in result && result.skipped) {
  console.warn('skipped', result.platform, result.reason);
} else if ('audienceId' in result) {
  console.log(result.platform, result.audienceId, result.verifiedSize);
}

// Option B — seed from your converters (lookalike seed)
const emails = audienceFromConversions(pastPurchases, {
  minValue: 100,
  events: ['purchase'],
});
await ads.audiences.sync({
  platform: 'meta',
  listName: 'purchasers-100plus',
  emails,
  consent: { adUserData: true, adPersonalization: true },
});

Related