Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.trygravity.ai/llms.txt

Use this file to discover all available pages before exploring further.

Overview

Track app installs back to the Gravity ad that drove them. Two integration paths:

Server-to-Server

Your backend calls the Gravity Conversions API when a user installs your app. Full control over data and timing.

MMP Postback

Your MMP (AppsFlyer, Adjust, etc.) fires postbacks to Gravity automatically. No code on your side.
Both paths write to the same conversion pipeline. Click-through and view-through attribution are supported.

How attribution works

  1. User sees or clicks a Gravity ad — Gravity captures a unique click identifier
  2. User lands on your website or App Store page
  3. User installs and opens your app
  4. The install is reported to Gravity (via your backend or MMP) with the click identifier
  5. Gravity attributes the install back to the originating campaign and ad
Gravity attribution does not depend on IDFA, so this works with iOS 14.5+ App Tracking Transparency restrictions.

Option 1: Server-to-Server

Best when you control the app backend and can capture the click identifier from the ad click URL.

Step 1: Capture the click identifier on your landing page

When a user arrives from a Gravity ad, the URL includes a click_id parameter:
https://yourapp.com/download?click_id=abc-123
Capture and persist it server-side:
const params = new URLSearchParams(window.location.search);
const clickId = params.get('click_id');

// Store server-side (preferred) or in a first-party cookie
fetch('/api/store-attribution', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ click_id: clickId }),
});
If you use a deep link provider (Branch, Firebase Dynamic Links, or a custom universal link), pass the click_id as a custom parameter so it survives the Web → App Store → App flow.

Step 3: Report the install

When the user opens your app for the first time, fire a conversion from your backend.
import requests
import hashlib
import time

API_KEY = "your-gravity-api-key"
GATEWAY_URL = "https://conversions.trygravity.ai/gateway/events"

def report_app_install(user, click_id):
    email_hash = hashlib.sha256(
        user["email"].strip().lower().encode()
    ).hexdigest() if user.get("email") else None

    payload = {
        "data": [{
            "event_name": "AppInstall",
            "event_time": int(time.time()),
            "event_id": f"install-{user['id']}-{int(time.time())}",
            "action_source": "app",
            "user_data": {
                "click_id": click_id,
                "em": [email_hash] if email_hash else None,
                "external_id": [str(user["id"])],
            },
            "custom_data": {
                "value": 0,
                "currency": "USD",
            }
        }]
    }

    return requests.post(
        GATEWAY_URL,
        json=payload,
        headers={"Authorization": f"Bearer {API_KEY}"},
        timeout=10,
    ).json()

Post-install events

Track in-app purchases and other downstream events with the same pattern:
payload = {
    "data": [{
        "event_name": "InAppPurchase",
        "event_time": int(time.time()),
        "event_id": f"purchase-{order_id}",
        "action_source": "app",
        "user_data": {
            "click_id": stored_click_id,
            "em": [email_hash],
            "external_id": [user_id],
        },
        "custom_data": {
            "value": 29.99,
            "currency": "USD",
            "order_id": order_id,
            "content_name": "Premium Subscription",
        }
    }]
}

App event types

Event NameInternal TypeWhen to fire
AppInstallapp_installFirst app open after install
AppOpenapp_openSubsequent app opens (re-engagement)
InAppPurchasein_app_purchaseIn-app purchase completed
Any custom stringLowercasedCustom app events

View-through attribution (no click)

If the user installs without clicking an ad (e.g., they saw the ad but went to the App Store directly), send the event without a click_id. Include the user’s email hash — Gravity will attempt to attribute the install to a recent ad impression.
payload = {
    "data": [{
        "event_name": "AppInstall",
        "event_time": int(time.time()),
        "event_id": f"install-{user_id}",
        "action_source": "app",
        "user_data": {
            "em": [email_hash],
            "client_ip_address": user_ip,
            "external_id": [user_id],
        },
        "custom_data": { "value": 0, "currency": "USD" }
    }]
}

Option 2: MMP Postback

Best when you already use an MMP. No code changes on your side — configure Gravity as a partner in your MMP dashboard.

Supported MMPs

MMPPostback URL
AppsFlyerhttps://conversions.trygravity.ai/mmp/postback/appsflyer
Adjusthttps://conversions.trygravity.ai/mmp/postback/adjust
Kochavahttps://conversions.trygravity.ai/mmp/postback/kochava
Branchhttps://conversions.trygravity.ai/mmp/postback/branch
Singularhttps://conversions.trygravity.ai/mmp/postback/singular
Otherhttps://conversions.trygravity.ai/mmp/postback?provider=<name>

Setup

1

Configure your click URL

In your MMP’s partner configuration for Gravity, ensure that the click identifier from Gravity’s ad URL is captured by the MMP as a custom parameter. Most MMPs call this clickid, click_id, or label.
2

Add the postback URL

In your MMP dashboard, add Gravity as a postback partner. Use the URL template for your MMP (see examples below).
3

Test the integration

Send a test postback to verify:
curl "https://conversions.trygravity.ai/mmp/postback/appsflyer\
?clickid=test-click-123\
&event_name=install\
&event_time=$(date +%s)\
&ip=203.0.113.50\
&app_id=com.example.app\
&api_key=YOUR_API_KEY"

Postback URL templates

https://conversions.trygravity.ai/mmp/postback/appsflyer
  ?clickid={clickid}
  &event_name={event_name}
  &event_time={event_time}
  &idfa={idfa}
  &ip={ip}
  &revenue={event_revenue}
  &currency={event_revenue_currency}
  &app_id={app_id}
  &country_code={country_code}
  &campaign={campaign_name}
  &api_key=YOUR_GRAVITY_API_KEY

MMP event mapping

The postback receiver normalizes common MMP event names:
MMP EventGravity Event Type
install, attributed_install, first_openapp_install
session, re_engagement, app_openapp_open
purchase, in_app_purchase, af_purchasein_app_purchase
registration, signupcomplete_registration
Custom eventsPassed through as-is (lowercased)

Response format

Both paths return the same structure:
{
  "status": "ok",
  "conversion_id": "uuid",
  "attributed": true,
  "event_type": "app_install",
  "provider": "appsflyer"
}
StatusMeaning
okProcessed and stored
duplicateAlready seen (deduplicated)
test_okTest mode — validated but not stored
errorProcessing failed

FAQ

No. Gravity does not depend on IDFA for attribution. This works with iOS 14.5+ App Tracking Transparency restrictions. If the user consented to tracking and you have IDFA, you can include it for additional signal, but it’s not required.
Send the conversion without click_id but include the user’s email hash (em). Gravity will attempt to attribute the install to a recent ad impression.
Yes. Use InAppPurchase (or any custom event name) with action_source: "app". Include custom_data.value for revenue attribution. Use the same click_id from the original install to maintain the attribution chain.
S2S gives you full control — you call the API from your backend with all available data. MMP is easier if you already use one — configure a URL template and the MMP handles the rest. Both feed into the same conversion pipeline.

Next

Pixel & web conversions

Track web conversions (purchases, signups, etc.).

Analytics

Reports, attribution windows, and ROAS.