Attribution

The attribution gap
every platform ignores

A user arrives from a Google ad, browses anonymously, creates an account two days later, and books on day four. Every major A/B platform counts that as three separate users. Tamda counts it as one.

See it in action

The problem

Most platforms only track identified users

A/B tools like Amplitude Experiment and LaunchDarkly assign users to variants at flag evaluation time. If the user isn't logged in, they either get a random anonymous bucket or they're excluded entirely.

The result: your experiment data doesn't reflect reality. A user who saw the treatment variant while anonymous and converted after login gets counted as two users: one anonymous exposure with no conversion, one new user with an unexplained conversion.

Your conversion rates are understated. Your attribution is wrong. Your Ship / Kill decisions are based on broken data.

User clicks Google ad

anonymousId: anon-7f3c

User sees treatment variant

Exposed, other platforms lose this

User browses for 2 days

Sessions tracked but not linked

User creates account

userId: usr_924, identity stitched

User completes booking

Conversion attributed to treatment

Red = dropped by other platforms. Tamda keeps the full chain.

The solution

Three primitives that fix attribution

Persistent anonymous ID

On first page load, a device ID is assigned and stored. This ID follows the user across sessions before they log in, capturing every experiment exposure, UTM source, and page event from the very first visit.

anonymousId: "anon-7f3c"

Identity stitching

When a user logs in, creates an account, or completes a purchase, you fire one identify call. Tamda links the anonymous ID to the known user ID and retroactively attributes all prior sessions and experiment exposures.

POST /api/identify

First-touch UTM attribution

UTM parameters are captured at the anonymous session level. When identity is stitched, the UTM data travels with it, so the booking that happened on day four is correctly attributed to the Google CPC click on day one.

utm: { source, medium, campaign }

API reference

Three endpoints. Full attribution.

POST/api/eventsTrack an exposure or conversion. Accepts either anonymousId (before login) or userId (after login), or both.
{
  anonymousId?: string   // persistent device ID
  userId?: string        // authenticated user ID
  sessionId?: string     // optional session grouping
  flagKey: string        // experiment identifier
  variant: string        // "control" | "treatment"
  type: "exposure" | "conversion"
  eventName?: string     // required for conversion
  utm?: {
    source?: string
    medium?: string
    campaign?: string
    content?: string
    term?: string
  }
}
POST/api/identifyLink an anonymous ID to a known user. Call this on signup, login, or purchase. All prior anonymous sessions are retroactively stitched.
{
  anonymousId: string    // the device ID to link
  userId: string         // the known user ID
  criteria?: string      // "signup" | "login" | "purchase"
}
GET/api/experiments/:id/attributionReturns first-touch UTM attribution for an experiment, grouped by source, medium, and campaign, with exposure and conversion counts.
// Response
{
  byChannel: [
    {
      source: "google",
      medium: "cpc",
      campaign: "brand",
      exposures: 1240,
      conversions: 89,
      conversionRate: 0.0718
    },
    ...
  ]
}

Stop losing conversions to broken attribution

Three API calls. No SDK. Works with your existing event system.

Read the docsGet started free