adscapi
v0.13.0
Published
One canonical conversion event, fanned out to every ad platform — server-side Conversions APIs + audience sync. SDK + CLI + MCP. "Stripe for ad-conversion tracking."
Maintainers
Readme
adscapi
One canonical conversion event, fanned out to every ad platform's server-side Conversions API and audience-sync API. Fire one typed event; adscapi hashes the identity, maps the event name per platform, and dispatches to each one you've configured.
Ships four ways from one package: an SDK you import, a CLI, an MCP server any agent can drive, and a hosted relay so a backend in any language can POST one event over HTTP.
import { createAdscapi } from 'adscapi';
const ads = createAdscapi(); // reads platform tokens from the environment
const results = await ads.conversions.track({
name: 'purchase',
value: 49,
currency: 'USD',
user: { email: '[email protected]' }, // raw — adscapi hashes advanced-matching fields per platform
clickIds: { fbclid: '…', gclid: '…' }, // captured server-side
consent: { adUserData: true, adPersonalization: true }, // optional: gppString, tcfString, limitedDataUse
});
// results: [{ platform: 'meta', ok: true }, { platform: 'tiktok', ok: false, error: '…' }, …]A platform is active only when its secrets are present, so the same call works
whether you run one platform or twenty-six. One platform failing never blocks the
rest — you get a result per destination instead of an exception. user accepts the
full advanced-matching set (name, city, state, zip, country, DOB, gender,
externalId, ip, userAgent, fbc/fbp); more match keys raise match rate and lower CAC.
consent also accepts optional IAB gppString / gppSectionIds / tcfString and a
limitedDataUse flag (CCPA). GA4 always gets Consent Mode (GRANTED/DENIED) so
Google can model conversions under signal loss; Meta gets Limited Data Use when the
flag is set.
Why
Every ad platform wants the same thing — "this user converted, here's the hashed identity" — but each has its own Conversions API, its own event names, its own token dance. The official SDKs are one platform each; the hosted tools (Servo, Stape) are no-code SaaS; the CDPs (Segment, RudderStack) are heavyweight and ad-tracking is a side feature. adscapi is the missing middle: a code-first library that does ad-conversion fan-out and nothing else.
What you get
- Conversions —
ads.conversions.track()fans one event to 26 platforms' server-side Conversions APIs. PII hashing, per-platform event mapping, cross-platform dedup, retries,dryRun, and a per-calldestinationstoggle are built in.track(event, { testEventCodes: { meta: 'TESTxxxxx' } })sends a real event to the platform's Test Events view (vsdryRun, which sends nothing). - Audiences —
ads.audiences.sync()uploads a hashed customer list to 28 platforms' audience APIs. - Offline imports —
uploadOffline()batch-uploads offline conversions from a CSV to Bing, Google Ads, and Meta. - Creatives —
uploadCreative()uploads an ad image (Meta today; more landing per PR). - Agent commerce —
fromAcpCheckoutSession()/fromAp2PaymentMandate()turn a settled ACP or AP2 agent purchase (no browser, no pixel) into a canonical event youtrack. So the ad that drove the agent still gets credit. Seedocs/AGENT-COMMERCE.md. - Measurement read-back —
getReport()pulls spend, impressions, conversions, and ROAS back from Meta, Google Ads, and TikTok to close the loop. Seedocs/REPORTING.md. - Governance —
Governorgates dispatch with a kill-switch, approval gate, rate cap, and audit trail for agents running under governed autonomy. Seedocs/GOVERNANCE.md. - Observability — a queryable, restart-safe delivery log via the
onResulthook. Seedocs/OBSERVABILITY.md. - AdCP interop — map results onto the AdCP
(metric_id, qualifier)measurement taxonomy. Seedocs/ADCP.md. - Four faces — the SDK above, a CLI, an MCP server for agents, and a hosted relay for non-JavaScript backends.
Run it from any language or runtime
- Import the SDK on any modern JS runtime — Node 18+, Bun, Deno, Next.js, and
edge runtimes like Cloudflare Workers. The dispatch path uses only
fetchand WebCrypto, no Node built-ins. - Any other language — run the hosted relay (a Cloudflare Worker) and POST one event to it over HTTP from Python, Ruby, Go, PHP, Rust, anything. Or shell out to the CLI from CI.
- Agents — point any MCP client at
npx adscapi mcp.
adscapi ships no per-framework SDK — there's one library, and you call it from your stack. The relay and CLI cover everything that isn't JavaScript.
CLI
npx adscapi platforms # every destination + the secrets it needs
npx adscapi init # interactive setup: prompts for missing secrets, writes .env
npx adscapi check # which platforms are configured right now
npx adscapi verify # live-check that configured tokens actually work
npx adscapi doctor # health check across configured platforms (nonzero exit on failure)
npx adscapi test-event --event purchase --email [email protected] --dry-run
npx adscapi offline --platform bing --file conversions.csv
npx adscapi creatives upload --platform meta --image https://cdn.example.com/hero.jpgdoctor exits non-zero when any configured platform fails its live check, so you can
run it in cron or CI as a health gate.
check reads your environment; verify goes further and calls each platform's API to
confirm the token is valid — so you catch an expired token before a real event does.
Hosted relay (non-JavaScript backends)
Deploy the Cloudflare Worker in worker/, set your platform secrets on it,
and any backend can fan out with one HTTP call:
curl -X POST https://<your-worker>/track -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-d '{"name":"purchase","value":49,"currency":"USD","user":{"email":"[email protected]"},"consent":{"adUserData":true,"adPersonalization":true}}'Platform secrets live on the Worker, never in the caller's request. See
worker/README.md.
MCP
// .mcp.json
{ "mcpServers": { "adscapi": { "command": "npx", "args": ["-y", "adscapi", "mcp"] } } }Lowering your CAC
Fan-out is table stakes; match quality is where cost per acquisition actually moves.
docs/MATCH-QUALITY.md is the playbook: which identifiers to
send, how to optimize for value, how to dedup and protect the signal under consent loss,
and how to read Meta's match-quality score as you tune.
Per-platform setup
Each destination has a setup guide in docs/platforms/: how to
create the account, where each token comes from, and how to verify it. Start with
Meta. Each conversion platform records the API doc it was
built against; npm run check:docs reports which are freshly verified and flags any
dead doc links.
Status
Live on npm. Twenty-six conversion platforms and twenty-eight audience-sync platforms
ship against their real API docs, plus offline CSV import (Bing, Google, Meta) and
image creatives (Meta). Five conversion platforms carry a live credential check today;
the rest are marked unverified and re-checked over time. The agent-native suite —
ACP/AP2 checkout adapters, spend/ROAS read-back, governance, a delivery log, and AdCP
measurement interop — ships alongside. Branch model: main is staging, release
publishes to npm.
License
MIT
