agentleFS
itsryanarmaniitsryanarmani/skills/ad-conversion-hub/SKILL.md

ad-conversion-hub

Skill1 starsChanged 4 days agoMITView on GitHub

Design and operate a shared ad-conversion hub for multiple ad platforms — canonical event taxonomy, consent gating, SHA-256 identity hashing, stable client/server deduplication, first-party click-id capture, platform adapter secrets, absent-secret no-ops, retry and failure isolation, server-side proof, and reconciliation against payment-provider truth. Use when a product sends one purchase, signup, lead, or subscription event to Google, Meta, Reddit, Microsoft, TikTok, LinkedIn, Pinterest, DSP, regional, CTV, or emerging ad platforms.

  • Reads credentials
  • Installs packages

1 other project uses a version of this.

Adopted by

Most recently taken up by

The file

Show its rules and text

We split this skill into the rules it gives an agent

19 rules. About 0 are common, 14 are distinctive, and 5 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈14

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 5

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Use one canonical event in the product.

    line 8
  2. Distinctive:

    Keep the event names stable across products and vendors:

    line 35
  3. Very specific:

    Use the payment-provider transaction ID for event_id when possible.

    line 48
  4. Distinctive:

    Read the consent record that belongs to the user and event time.

    line 103
  5. Distinctive:

    Keep a reason when the hub skips an adapter.

    line 107
  6. Distinctive:

    Keep raw identifiers inside the server boundary.

    line 125
  7. Distinctive:

    Never use a click ID as the condition for sending a server purchase.

    line 134
  8. Distinctive:

    Every platform adapter has the same shape:

    line 144
  9. Distinctive:

    Use the shared secret names from the platform skill.

    line 158
  10. Very specific:

    If the browser and server send one event, both must carry the same event ID.

    line 173
  11. Distinctive:

    Keep a dispatch record with:

    line 177
  12. Distinctive:

    Do not retry a request when the vendor may have accepted it and the response was lost, unless the vendor documents idempotency.

    line 187
  13. Distinctive:

    Do not retry 400, 401, 403, or policy errors without changing the request or credential.

    line 194
  14. Distinctive:

    Do not call a pixel network request proof.

    line 210
  15. Distinctive:

    Test each adapter with:

    line 215
  16. Distinctive:

    Keep server tokens in the deployment secret store.

    line 233
  17. Very specific:

    Use the platform-specific *-ads skill for vendor endpoints and console steps.

    line 242
  18. Very specific:

    Use ad-experiments for hypothesis design, seed sizing, and budget control.

    line 243
  19. Very specific:

    Use ads-google, ads-meta, and ads-reddit as detailed examples of adapter pitfalls and server-side verification.

    line 244

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

ad-conversion-hub

Use one canonical event in the product. Adapt it at the platform edge.

The hub owns business truth. A platform skill owns vendor syntax. This split keeps checkout code free from vendor-specific fields and makes a new adapter a small change.

Flow

payment provider webhook
        |
        v
canonical event -> consent gate -> identity normalizer -> adapter fan-out
        |                  |                 |
        |                  |                 +--> client/server dedup key
        |                  +--------------------> hashed identifiers only
        +----------------------------------------> payment-provider event ID
                                                     |
                                                     v
                                         platform event + durable dispatch log

The payment provider is the source of truth for a successful charge. Ad platform dashboards are attribution views. They are not the ledger.

Canonical event taxonomy

Keep the event names stable across products and vendors:

Canonical eventWhen it firesRequired fields
page_viewA page or SPA route loadsevent_id, occurred_at, page_url
view_contentA meaningful product or plan view occursevent_id, content_id
leadA user submits a qualified lead formevent_id, lead_id
signupAn account is createdevent_id, user_id
begin_checkoutA checkout session startsevent_id, checkout_id, currency
purchaseThe payment provider confirms a chargeevent_id, order_id, value, currency
subscription_startA paid subscription becomes activeevent_id, subscription_id, value, currency
refundA payment provider records a refundevent_id, order_id, value, currency

Use the payment-provider transaction ID for event_id when possible. Use a separate event ID for a refund. Do not reuse the purchase ID for a later event.

Event envelope

The hub stores a normalized envelope before dispatch:

type CanonicalAdEvent = {
  event_id: string;
  event_name:
    | 'page_view'
    | 'view_content'
    | 'lead'
    | 'signup'
    | 'begin_checkout'
    | 'purchase'
    | 'subscription_start'
    | 'refund';
  occurred_at: string; // ISO 8601 UTC
  source: 'browser' | 'server' | 'webhook' | 'offline';
  order_id?: string;
  checkout_id?: string;
  subscription_id?: string;
  user_id?: string;
  value?: number;
  currency?: string;
  page_url?: string;
  click_ids?: Record<string, string>;
  identity?: {
    email?: string;
    phone?: string;
    ip_address?: string;
    user_agent?: string;
  };
  consent: {
    ad_user_data: boolean;
    ad_personalization: boolean;
    measurement: boolean;
  };
  items?: Array<{
    item_id: string;
    quantity?: number;
    price?: number;
  }>;
};

Reject an event that has no stable event_id, no event_name, or no consent decision. Do not reject a purchase only because it has no ad click ID.

Consent gate

Apply consent before hashing or dispatch:

  1. Read the consent record that belongs to the user and event time.
  2. Require measurement: true before sending any ad event.
  3. Require ad_user_data: true before sending hashed email, phone, or external IDs.
  4. Require ad_personalization: true before adding a user to a retargeting or lookalike audience.
  5. Keep a reason when the hub skips an adapter.

Consent does not mean that every platform may receive every field. Each adapter must reduce the envelope to the fields allowed by its current official docs.

Identity normalization and hashing

Normalize email as trim → lowercase → UTF-8 → SHA-256 hex. Normalize phone with the platform's current country-code rules before hashing. Do not hash an already hashed value a second time.

function sha256Email(email: string): string {
  const normalized = email.trim().toLowerCase();
  return sha256Hex(normalized);
}

Keep raw identifiers inside the server boundary. The adapter receives a short-lived normalized value or a hash. It must not log either one.

Click IDs

Capture the platform click ID on first landing when it appears in the URL. Persist it in first-party storage with a defined retention period. Keep the first-touch and most-recent value separately when the platform supports both.

Never use a click ID as the condition for sending a server purchase. Organic, direct, email, and SEO purchases still provide useful measurement and can match through hashed identity or first-party identifiers.

Each adapter owns its click-ID name. Examples include gclid, fbclid or fbc, msclkid, ttclid, qclid, and platform-specific values. Confirm every name against the platform's official docs before adding it to the hub.

Adapter contract

Every platform adapter has the same shape:

type AdAdapter = {
  platform: string;
  requiredSecrets: string[];
  dispatch(event: CanonicalAdEvent): Promise<{
    status: 'sent' | 'skipped' | 'failed';
    request_id?: string;
    reason?: string;
  }>;
};

Use the shared secret names from the platform skill. The usual convention is:

<PLATFORM>_PIXEL_ID   public client identifier
<PLATFORM>_TAG_ID     public tag or data-source identifier
<PLATFORM>_CAPI_TOKEN  server conversion credential
<PLATFORM>_ACCESS_TOKEN server API credential

A missing required secret returns skipped. It does not throw. A 4xx or 5xx response returns failed, records a redacted error, and does not fail the payment webhook.

Client and server deduplication

If the browser and server send one event, both must carry the same event ID. Some platforms use eventID, event_id, conversionId, or another casing. The adapter translates the field. The hub does not change the value.

Keep a dispatch record with:

  • canonical event_id;
  • platform name;
  • adapter event name;
  • first attempt time;
  • response status and request ID;
  • redacted error code;
  • retry count.

Do not retry a request when the vendor may have accepted it and the response was lost, unless the vendor documents idempotency. If the vendor supports a test event mode, use it before production dispatch.

Retry policy

  • Retry network timeouts and 5xx responses with bounded exponential backoff.
  • Do not retry 400, 401, 403, or policy errors without changing the request or credential.
  • Honor Retry-After when the vendor sends it.
  • Cap retries so a webhook cannot run past its provider timeout.
  • Move exhausted events to a durable dead-letter queue.
  • Replay only after checking the vendor's deduplication rule.

Verification

Verification has three layers:

  1. Request proof: the adapter receives a documented success response.
  2. Platform proof: the official test-event view, event history, read endpoint, or reporting API shows the event.
  3. Business proof: the platform result is reconciled with payment-provider succeeded charges, refunds, and subscription state.

Do not call a pixel network request proof. Do not call a 200 response platform proof. Do not call an attributed conversion count business proof.

Testing checklist

Test each adapter with:

  • a purchase with consent and a click ID;
  • a purchase with consent and no click ID;
  • a purchase without ad-user-data consent;
  • a duplicate delivery with the same event ID;
  • an absent token;
  • a 401 response;
  • a timeout followed by a replay;
  • a refund after a purchase;
  • a currency and value edge case;
  • a successful payment with a failed ad dispatch.

The last case must show a successful payment and a retryable ad failure. The ad integration must never roll back the payment.

Security

Keep server tokens in the deployment secret store. Do not put them in client bundles, URLs, logs, analytics payloads, screenshots, or pull requests. Load vendor scripts only from the official HTTPS origin documented by each platform.

Limit access to raw identity data. Delete temporary normalized identifiers after dispatch. Record consent and retention decisions with the event metadata.

Pairing

Use the platform-specific *-ads skill for vendor endpoints and console steps. Use ad-experiments for hypothesis design, seed sizing, and budget control. Use ads-google, ads-meta, and ads-reddit as detailed examples of adapter pitfalls and server-side verification.

Shipped as a package

Productize this hub as an npm package — the SDK + CLI + MCP form of this skill, so a consumer runs npm i <your-package> instead of re-implementing the flow. Learnings from the extraction, reusable here:

  • Namespaced client surface (Stripe/Segment shape): createClient() reads secrets from env → ads.conversions.track(event) returns a per-destination result array { platform, ok, error }[]; ads.destinations.list() / .verify().
  • Adapters throw, the client isolates. Each dispatcher throws on non-2xx; the client wraps with retry + captures per-destination so one platform's failure never blocks the rest. (Do NOT copy the fire-and-forget swallow model from an in-request backend — see agentic-cli-npm-package §6.)
  • verify ≠ check. check = secrets present; verify = hit the platform API to prove the token works. Ship a per-platform optional verify(secrets) alongside each dispatch.
  • The registry is the seam. PLATFORMS[key] = { dispatch, verify?, support, requiredSecrets }, append-only so parallel platform PRs never conflict. support: real-capi | offline-upload | pixel-only — no platform is a silent no-op.
  • Per-platform runbook (docs/platforms/<key>.md): create-account → where each token comes from → verify → event mapping → troubleshooting. Pairs with agent-harness-docs.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.