Measura

Migration Guide

Bring your history from AppsFlyer, Adjust or Branch, and take it out again whenever you want.

What the importer does

The migration importer takes an export from your current attribution platform and loads it into Measura as historical events, installs and attribution records. Your cohort charts and channel breakdowns then include the period before you switched.

Imported attributions are preserved as the source reported them. We do not re-run our matching over historical data, because the click level signals needed to do that are not in any platform’s export. Imported records carry a confidence score of zero and a written reason recording where they came from, so they are never confused with attributions Measura resolved itself.

Supported sources

AppsFlyer, Adjust and Branch have built in column mappings. A custom option accepts a file whose columns already use Measura field names.

Preparing your export

File requirements

RequirementValue
FormatsCSV or JSON (an array of objects)
Maximum size5 MB per upload
Maximum rows50,000 per upload
Content typetext/csv, application/json or text/plain
EncodingUTF-8

Larger histories are imported as a sequence of uploads. Split by date range so a failed batch is easy to identify and re-run.

Which columns to include

Export everything your platform offers. Unmapped columns are ignored rather than rejected, so a wider export costs nothing. At minimum, include the event timestamp, the event name, and at least one device identifier.

AppsFlyer column mapping

Use the raw data export. These columns are recognised automatically.

AppsFlyer columnMeasura field
Install Timeinstalled_at
Event Timeevent_timestamp
Event Nameevent_type
AppsFlyer IDexternal_device_id
Advertising IDgaid
Campaigncampaign_name
Media Sourcechannel
Attribution Typeattribution_model
Revenuerevenue
Currencycurrency
Country Codecountry_code
IPip
Device Typedevice_model
OS Versionos_version
App Versionapp_version

Adjust column mapping

Adjust columnMeasura field
installed_atinstalled_at
eventevent_type
gps_adidgaid
network_namechannel
campaign_namecampaign_name
attribution_typeattribution_model
revenue_usdrevenue
countrycountry_code
ip_addressip
device_namedevice_model
os_nameos_name
os_versionos_version
app_versionapp_version

Branch column mapping

Branch columnMeasura field
Timestampevent_timestamp
Nameevent_type
AAIDgaid
Channelchannel
Campaigncampaign_name
Revenuerevenue
Countrycountry_code
OSos_name
OS Versionos_version
App Versionapp_version

Branch exports carry no dedicated install time column, so the event timestamp is used for install rows.

Custom exports

Choosing custom applies no column translation. Your file must already use Measura field names.

Custom JSON exportjson
[
  {
    "event_timestamp": "2026-05-14T08:31:02Z",
    "installed_at": "2026-05-14T08:31:02Z",
    "event_type": "install",
    "gaid": "38400000-8cf0-11bd-b23e-10b96e40000d",
    "channel": "whatsapp",
    "campaign_name": "lagos-launch-may",
    "attribution_model": "deterministic",
    "revenue": 0,
    "currency": "USD",
    "device_model": "Samsung SM-A245F",
    "os_name": "android",
    "os_version": "14",
    "app_version": "2.1.0"
  }
]

This is also the route for a platform we do not map natively. Rename the columns in your export tooling, then import as custom.

How values are normalised

Channels

Source network names are translated to Measura channels. Anything unrecognised is lowercased with spaces replaced by underscores and carried through as is.

Source valueMeasura channel
Facebook Ads, facebookmeta
Google AdWords, google_adsgoogle
TikTok Adstiktok
Twitter Adstwitter
WhatsAppwhatsapp
Emailemail
SMSsms
organic, Organicorganic

Event types

Source valueMeasura event type
install, af_installinstall
open, sessionopen
session_startsession_start
purchase, revenue, af_purchasepurchase
anything elsecustom

Attribution models

Source value containsMeasura model
organicorganic
deterministic, device_iddeterministic
probabilistic, fingerprintprobabilistic
anything elselast_click

IP addresses are truncated on import too

Any IP address in your export is masked to its network block before storage, exactly as it would be during live ingestion. No raw address from a historical file is written either.

Running an import

The developer dashboard provides this flow under Migrate. To automate it, call the three endpoints directly.

  1. 1.Create the job. Returns a job identifier and the column mapping that will be applied, so you can confirm the mapping before committing the data.
  2. 2.Upload the file. Processing begins immediately, in batches of 100 rows.
  3. 3.Poll for status. Reports rows processed, a percentage, and any row level errors.
Full import sequencebash
# 1. Create the job
curl -X POST "$MEASURA_HOST/functions/v1/migration-importer/start" \
  -H "Authorization: Bearer $SESSION_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"app_id":"7d2e5b1a-...","source_platform":"appsflyer"}'

# → {"job_id":"c4a9...","column_mapping":{...}}

# 2. Upload the export
curl -X POST "$MEASURA_HOST/functions/v1/migration-importer/upload?job_id=c4a9..." \
  -H "Authorization: Bearer $SESSION_TOKEN" \
  -H "Content-Type: text/csv" \
  --data-binary @appsflyer-export.csv

# → {"job_id":"c4a9...","total_rows":24500,"status":"processing"}

# 3. Poll until complete
curl "$MEASURA_HOST/functions/v1/migration-importer/status?job_id=c4a9..." \
  -H "Authorization: Bearer $SESSION_TOKEN"

# → {"status":"completed","processed_rows":24500,"progress_pct":100,"errors":[]}

Full request and response detail is in the API Reference.

Interpreting the result

Success and failure

A job completes when fewer than five percent of rows produced errors. At or above that threshold the job is marked failed, on the basis that a systematic problem such as a wrong platform selection or a malformed file should not be quietly half applied.

Rows that error are listed individually in the status response with the reason, so you can correct and re-upload just those.

What imported records look like

  • Marked as already processed, so they do not enter the live attribution queue.
  • A confidence score of 0 and a reason recording the source platform. Imported history is never mixed with scores Measura computed.
  • Postback status skipped, so importing history never fires conversion notifications to advertising networks.
  • A user agent of migration-import/{platform} and a fraud score of zero.
  • An idempotency key derived from the job and row position, so re-uploading the same file into the same job does not duplicate rows.

Re-uploading creates duplicates across jobs

Idempotency is scoped to a job. Uploading the same file under a new job will import the rows again. If an import goes wrong, contact us to clear it rather than re-running against a fresh job.

Migrating away from Measura

This guide is mostly about coming in, so it is worth being just as clear about going out. You can export everything Measura holds for your account at any time, without asking us, and without a fee.

Export your accountbash
curl -X POST "$MEASURA_URL/rest/v1/rpc/export_my_account_data" \
  -H "apikey: $ANON_KEY" \
  -H "Authorization: Bearer $SESSION_JWT" \
  -H "Content-Type: application/json" \
  -d '{}' > measura-export.json

The export contains your apps, campaigns, short links, installs, attributions with their full confidence breakdown, raw events, fraud flags and payment records, plus a totals block so you can check nothing was truncated.

What to do about the SDK

Remove the Measura dependency and the initialisation call. Nothing is left behind on the device except the local event queue, which is cleared when the app is uninstalled. There is no server call required to deactivate.

Deleting what we hold

Exporting does not delete. When you have your data and have confirmed it is complete, raise a deletion request from the dashboard and the account is erased on approval. Deletion is irreversible, which is why it is a separate, deliberate step rather than a side effect of exporting.

Why this page exists

A platform that makes leaving difficult is relying on friction rather than on being worth staying with. The same import mappings above work in reverse for anyone reading this document from the other direction.

After the import

  1. 1.Check your totals. Compare installs by month in the Measura dashboard against the same period in your previous platform. Small differences are expected, since deduplication and event type normalisation are not identical. Large ones are worth investigating before you switch over.
  2. 2.Run both platforms in parallel. Keep the old SDK alongside Measura for two to four weeks. Comparing live numbers is the only reliable way to build confidence in the switch.
  3. 3.Expect attribution differences. Measura declines to report matches below its confidence floor and reports them as organic instead. Your attributed share may look lower than your previous platform reported, with a corresponding rise in organic. That gap is the point rather than a defect, and the confidence score page explains the arithmetic.
  4. 4.Then remove the old SDK. Once the numbers reconcile and your team trusts the new figures.

Migrating a large history, or coming from a platform not listed here? Talk to us and we will work through it with you.