Quick Start

Get events flowing in under 5 minutes.

1. Sign up and get your API key

Go to the dashboard, create an account, and generate an API key.

2. Send a test event

curl -X POST https://crosstrack.onrender.com/v1/events \
  -H "Content-Type: application/json" \
  -H "X-API-Key: YOUR_API_KEY" \
  -d '{
    "anonymousId": "test-visitor-001",
    "type": "page_view",
    "properties": {"url": "/hello"}
  }'

If you get a 201 Created response with a profileId, you're connected.

3. Integrate an SDK

Pick your platform below and follow the guide.

Web SDK

Install

<script src="https://app.crosstrackdata.com/crosstrack.js"></script>

Initialize

CrossTrack.init({
  apiKey: 'YOUR_API_KEY',
  collectionUrl: 'https://crosstrack.onrender.com'
});
CrossTrack.consent('opted_in');

Track events

// Page view (automatic if autoPageView is true)
CrossTrack.page();

// Custom event
CrossTrack.track('button_click', { button: 'signup', page: '/pricing' });

Identify users

// When a user logs in
CrossTrack.identify('user_123', {
  email_hash: 'sha256_of_email'
});

Configuration options

OptionDefaultDescription
apiKeyrequiredYour API key from the dashboard
collectionUrlrequiredCrossTrack backend URL
autoPageViewtrueAutomatically track page views
flushIntervalMs30000How often to send batched events (ms)
maxQueueSize500Max events to queue before dropping oldest

Methods

MethodDescription
CrossTrack.init(config)Initialize the SDK
CrossTrack.consent(state)Set consent: 'opted_in', 'opted_out', or 'not_set'
CrossTrack.track(type, props)Track a custom event
CrossTrack.page(props)Track a page view
CrossTrack.identify(userId, traits)Link anonymous session to a known user
CrossTrack.flush()Flush event queue immediately
CrossTrack.reset()Clear user state and visitor ID
CrossTrack.getVisitorId()Get the current visitor ID
CrossTrack.shutdown()Stop tracking and flush remaining events

Android SDK

Install

Add JitPack to settings.gradle.kts:

dependencyResolutionManagement {
    repositories {
        maven { url = uri("https://jitpack.io") }
    }
}

Add the dependency to build.gradle.kts:

implementation("com.github.CrossTrackData:crosstrack-android:0.1.0")

Initialize

// In your Application class
CrossTrack.init(
    context = applicationContext,
    config = CrossTrackConfig(
        apiKey = "YOUR_API_KEY",
        collectionUrl = "https://crosstrack.onrender.com"
    )
)
CrossTrack.consent().setConsent(ConsentState.OPTED_IN)

Track events

CrossTrack.api().track("screen_view", mapOf("screen" to "home"))
CrossTrack.api().screen("checkout")

Identify users

CrossTrack.api().identify("user_123")

WebView bridge

// Automatically bridges app and WebView identity
webView.webViewClient = CrossTrackWebViewClient(webView)

iOS SDK

Install

In Xcode: File → Add Package Dependencies → paste:

https://github.com/CrossTrackData/crosstrack-ios

Initialize

CrossTrack.shared.initialize(
    config: CrossTrackConfig(
        apiKey: "YOUR_API_KEY",
        collectionUrl: "https://crosstrack.onrender.com"
    )
)
CrossTrack.shared.consent().optIn()

Track events

CrossTrack.shared.track("screen_view", properties: ["screen": "home"])

Identify users

CrossTrack.shared.identify("user_123", traits: ["email_hash": "sha256..."])

WebView bridge

CrossTrack.shared.installBridge(on: myWebView)

API Reference

All endpoints require the X-API-Key header.

POST /v1/events

Send a single event.

{
  "anonymousId": "visitor-abc",
  "type": "page_view",
  "properties": { "url": "/pricing" },
  "context": {
    "platform": "web",
    "sessionId": "sess-123"
  }
}

POST /v1/events/batch

Send multiple events at once.

{
  "events": [
    { "anonymousId": "visitor-abc", "type": "page_view", "properties": {} },
    { "anonymousId": "visitor-abc", "type": "button_click", "properties": {} }
  ]
}

POST /v1/identify

Link an anonymous session to a known user. Triggers profile merge if the userId is already associated with a different profile.

{
  "anonymousId": "visitor-abc",
  "userId": "john",
  "traits": { "email_hash": "sha256_of_email" }
}

GET /v1/events

Query events. Parameters: since (ISO timestamp, required), limit (default 100, max 1000).

GET /v1/events?since=2026-01-01T00:00:00Z&limit=50

GET /v1/profiles

List profiles updated since a given timestamp. Parameters: since (ISO timestamp, required), limit (default 100, max 1000).

GET /v1/profiles?since=2026-01-01T00:00:00Z&limit=100

GET /v1/profiles/{id}

Get a profile by its profile ID.

GET /v1/profiles/lookup

Look up a profile by any identifier. Parameters: type (VISITOR_ID, USER_ID, EMAIL_HASH, PHONE_HASH), value.

GET /v1/profiles/lookup?type=USER_ID&value=john

Getting Your Data Out

CrossTrack resolves identity — your warehouse, BI tool, or backend is where you analyze it. Here's how to pull resolved data.

Poll resolved events

Fetch events with resolved profileId attached. Poll on a schedule (e.g. every 5 minutes) and load into your warehouse.

curl https://crosstrack.onrender.com/v1/events?since=2026-04-01T00:00:00Z&limit=1000 \
  -H "X-API-Key: YOUR_API_KEY"

Each event includes the unified profileId — so even if the original event came from an anonymous session, you get the resolved identity.

Sync all profiles

Fetch profiles updated since a given timestamp. Use this to sync resolved profiles into your warehouse on a schedule.

curl "https://crosstrack.onrender.com/v1/profiles?since=2026-04-01T00:00:00Z&limit=1000" \
  -H "X-API-Key: YOUR_API_KEY"

Returns all profiles with their linked user IDs, anonymous IDs, email hashes, and traits. Paginate by advancing the since parameter to the lastSeen of the last profile returned.

Look up a single profile

Query a full profile by user ID, visitor ID, or email hash. Useful for enriching your CRM or personalizing in real-time.

# By user ID
curl "https://crosstrack.onrender.com/v1/profiles/lookup?type=USER_ID&value=john" \
  -H "X-API-Key: YOUR_API_KEY"

# By anonymous visitor ID
curl "https://crosstrack.onrender.com/v1/profiles/lookup?type=VISITOR_ID&value=cb221dda-..." \
  -H "X-API-Key: YOUR_API_KEY"

Returns the full profile: all linked user IDs, anonymous IDs, email hashes, traits, and event history.

Coming soon

Webhook push and warehouse connectors (BigQuery, Snowflake) are on the roadmap. Vote for what you need — it directly affects what we build next.

How Identity Resolution Works

CrossTrack maintains an identity graph that links anonymous visitor IDs to known user identities.

Profile creation

When a new anonymousId is seen for the first time, a new profile is created.

Login merge

When you call identify(userId), CrossTrack links the anonymousId to the userId. If that userId already belongs to a different profile, the two profiles are merged — all historical events from both profiles are unified under a single profileId.

WebView bridge

When a user opens a WebView inside your app, the native SDK injects the app's visitor ID into the WebView's localStorage. The Web SDK reads it and sends it as context.bridgeId. The server links both IDs to the same profile — no login required.

Deterministic matching

Profiles are merged when they share any of these identifiers:

  • User ID — same userId on different anonymous sessions
  • Email hash — same hashed email across platforms
  • Phone hash — same hashed phone number
  • Bridge ID — WebView bridge linking app and web

Troubleshooting

Getting 401 Unauthorized

Check that your X-API-Key header is set correctly. Copy the key from your dashboard — it starts with ct_live_.

Events not showing in dashboard

  • Make sure consent is set to opted_in before tracking
  • Call flush() to send events immediately (otherwise they batch every 30s)
  • Check browser console for network errors

Profiles not merging

Profiles only merge when they share an identifier. Make sure identify() is called with the same userId on both platforms.

WebView bridge not working

  • Ensure consent is opted_in before the WebView loads
  • The bridge key in localStorage is crosstrack_device_id
  • Check that the domain is in the allowlist (if configured)

Slow first request

On the free tier, the backend sleeps after 15 minutes of inactivity. The first request takes ~30 seconds to wake up. Subsequent requests are fast.

Coming Soon

These features are on our roadmap. Vote for what matters most to you.

Warehouse Connectors

Direct delivery to BigQuery, Snowflake, and Redshift.

Webhook Push

Push resolved events to your endpoint in real-time.

Segment Integration

Add identity resolution on top of your existing Segment pipeline.

Real-Time Profile API

Query a user's full resolved profile for personalization.

Probabilistic Matching

IP + device fingerprinting with confidence scores.

React Native / Flutter SDKs

Cross-platform mobile SDK support.

Have a different request? Tell us what you need.