pixellint

A CDP is a pipe. A pixel is a bid.

Short answer

Marketers turn on the Meta destination in Segment and assume Event Match Quality. Engineers assume the destination mapping hashes email. Someone should open the actual POST.

Validate this snippet Open the rulepack

Three schemas, one dictionary

Your product event name, GA4 recommended events, Meta standard events. A map with tests. Without it you ship Purchse to one and purchase to another. Segment track event is a string you chose. GA4 purchase is a recommended name with ecommerce params. Meta Purchase is PascalCase with event_id. The CDP will not translate unless a mapping says so.

Product analytics (PostHog, Mixpanel, Amplitude) wants funnels and retention. Ads CAPI wants matchable conversions for bidding. GA4 MP wants a G- stream and 16-digit micros. One track() is not automatically all three jobs done well. Write two columns on the dictionary: product and ads.

Bare bodies are not interchangeable

Segment and PostHog both post a root event. A bare body has no URL. Pixellint tells them apart by writeKey, userId, anonymousId versus api_key, distinct_id. Mixpanel is a bare array with properties.token. Amplitude is api_key plus events[].event_type. Shipping the wrong envelope still 200s at the wrong host, or matches no pack.

Validate the source call and the destination body. pixellint validate json --rulepack vendor/segment on the batch, then vendor/meta-conversions-api on the POST the Meta destination emitted. HTTP 200 from Segment is not Event Match Quality.

pixellint validate json @segment-batch.json --rulepack vendor/segment
pixellint validate json @meta-capi.json --rulepack vendor/meta-conversions-api

Klaviyo and Braze are not Segment

Klaviyo Create Event is JSON:API. data.type must be event. The metric name lives at data.attributes.metric.data.attributes.name. A profile identifier is required: id, email, phone number, or external id. Pixellint: vendor.klaviyo.body.data.type.invalid, metric name missing, profile_needs_an_identifier. Copying a Segment track here fails the resource type before anything else runs.

Braze POST /users/track wants events[].name, ISO 8601 time, and one of external_id, user_alias, braze_id, email, or phone. Purchases need product_id, ISO 4217 currency, and price. Epoch timestamps fail the time contract. A dollar sign is not a currency code. These are messaging and lifecycle pipes. They still need a person. They are not Meta CAPI.

{
  "data": {
    "type": "event",
    "attributes": {
      "metric": {"data": {"type": "metric", "attributes": {"name": "Placed Order"}}},
      "profile": {"data": {"type": "profile", "attributes": {"email": "buyer@example.com"}}}
    }
  }
}

When to go direct

Purchase CAPI from the shop backend, product events through the CDP, is a common split. Dedup still needs a shared event_id when both touch Meta (fbq eventID on the pixel, event_id on CAPI, same string). A CDP destination that mints its own UUID and a backend that mints another is two purchases.

Pixellint is not affiliated with Segment, Meta, Klaviyo, or Braze. Pack pages under /packs/ are the field tables. This article is the routing decision. Open the actual POST.

Check the artifact

Paste the pixel URL or JSON body into the playground. Same engine as pixellint validate. Artifacts you test may be stored; see privacy.