Migrate
Migrate from AppsFlyer OneLink
Move your OneLink links to Appy with a checked import. This guide covers which exports to use, what carries over, what happens to the two-part OneLink path and to your branded domain, and what stays with AppsFlyer.
Before you start
- The import is in the dashboard under Links > Import links and on the REST API as
POST /v1/links/import(Business and Enterprise). - Every plan can import within its link limit: Free 4, Pro 10, Business 500, Enterprise without a limit. Custom paths and deep links need Pro, custom domains need Business.
- One file holds up to 1000 links and 2 MB in the dashboard, or 480 KB per API request.
Nothing moves until you say so
The import first runs a check that writes nothing and shows every link: its new address, where each device goes and what is left behind. Links are created only when you confirm, and your OneLink setup keeps working throughout.
1. Export your links from AppsFlyer
| Export | Where | What it contains |
|---|---|---|
| OneLink links CSV | Engage > OneLink Management, choose the template, then Export | Links created in the AppsFlyer interface, one template at a time: Link name, Media source, Campaign name, Short link, long link, Last modified, Modified by. The long link carries every parameter in its query string, and the import reads them from there. |
| Bulk links CSV | The file you uploaded under Engage > Bulk links | Custom Link ID plus parameter columns such as pid, c, af_dp and deep_link_value. It has short link IDs but no full links, so enter your link domain under Defaults. |
| OneLink API v2 | GET /api/v2.0/shortlinks/{onelink-id}/{shortlink-id}, one link per call | The link’s parameters as payload, for any link, including links created with the API or SDK |
The interface export misses some links
AppsFlyer’s export covers only links created in its interface. Links made with the SDK, the OneLink API or bulk upload are not in it, and a link edited later through the API exports its old parameters. OneLink has no endpoint that lists links, so start from your own list of those short links and read each one with the OneLink API v2. Put the short link in a url column and the response in a payload column.
Any CSV works as long as it has a header row. Columns named after OneLink parameters (af_ios_url, pid), a Short link or url column, a shortlink_id or Custom Link ID column, a long link column and a payload JSON column are all read. Comma, semicolon and tab separators are detected automatically.
2. What carries over
| OneLink parameter | In Appy |
|---|---|
af_web_dp | Website: where computers and devices without a target go |
af_r | Website when there is no af_web_dp. Like in OneLink, it also covers phones that have no URL of their own; af_ios_url and af_android_url take priority. |
af_ios_url | iPhone target. iPads use it too. |
af_android_url | Android target |
af_dp | Deep link (Pro and above) |
deep_link_value, deep_link_sub1 to deep_link_sub10 | Query parameters on the deep link, for example acme://open?deep_link_value=spring, so the app reads the same values from the URL. Without af_dp, enter your app’s URI scheme under Defaults. |
pid, af_channel, c | utm_source, utm_medium and utm_campaign on the website URL, unless the URL already has them. This mapping is Appy’s choice; store URLs get no UTM tags. |
Link name, then af_og_title | Link title in the dashboard |
af_og_title, af_og_description, af_og_image | Social preview: the card chat apps and social networks show when the link is shared (Pro and above). Without af_og_title, the link name is used. The image has to be an https address. |
| Short link ID | The link’s path, when it fits Appy’s rules (see step 4) |
Not carried over
The report lists every parameter that does not move, for every link, so nothing disappears without a note. The most common ones:
- Attribution parameters:
af_adset,af_ad,af_sub1toaf_sub5,af_prt,af_click_lookback,is_retargeting,af_cost_*. Appy records the UTM tags of each click instead. - Behaviour parameters:
af_force_deeplink,af_xp,af_param_forwarding,renew_ttl. - Custom parameters that your app reads through the AppsFlyer SDK. Put what the app needs into
af_dpordeep_link_value. - Fields AppsFlyer generates, such as
ttl,expiry, Last modified and Modified by, are listed as ignored. - Click and install history stays in AppsFlyer. Appy counts clicks from the moment a link is imported.
3. Run the import
- 1
Upload
Open Links > Import links, choose AppsFlyer OneLink and add the CSV. Under Defaults, fill in what your links leave out: the website, the App Store and Google Play pages, your app’s URI scheme and, for files without full links, the old link domain. Template-level redirects in OneLink are not part of the link, so exports often leave them out. Rows that set their own value keep it.
- 2
Preview
See which column went where, which keys are not carried over and which domains the links use, with what each domain needs to keep working.
- 3
Check
Every link is validated without writing anything: the path rules, every URL, the domain blocklist and your plan’s link limit. Each link shows its new address, where each device goes and a note for anything that changes. Download the report to share it or to plan reprints.
- 4
Import
The links that are ready are created in file order until your plan’s link limit is reached; the rest are reported as over the limit. Run the same file again after fixing a row: links already in your account are skipped.
4. Paths and printed links
A OneLink short link has a template ID and a short link ID, as in click.acme.com/A1bc/spring. Appy links have a single part, so the import uses the short link ID as the path: click.acme.com/spring once the domain is on Appy, and appy.to/spring everywhere. The ID becomes the path when it has 5 to 64 letters, numbers or dashes, is not reserved and is not used by another Appy account; otherwise the link gets a new five-character path and the report says why.
| Old link | What happens |
|---|---|
On your branded domain, such as click.acme.com/A1bc/spring | The domain can move: add it under Custom domains (Business and Enterprise) and change its CNAME to cname.appy.to. The new links are click.acme.com/spring. The old two-part paths do not open on Appy, so printed QR codes need the new link. |
On onelink.me, such as acme.onelink.me/A1bc/spring | This domain belongs to AppsFlyer and cannot point to Appy. Share or reprint the new link. |
Short link ID shorter than 5 characters, with _, reserved or taken | The link gets a new path, listed in the report with the reason. |
Printed codes on a branded domain: plan the switch
When the CNAME points to Appy, AppsFlyer no longer serves the domain and deletes it from your OneLink setup, and every old two-part path opens your root redirect URL or a not-found page. If QR codes with the old paths are still in circulation, keep that domain on OneLink until they are replaced and put your Appy links on a new subdomain, such as go.acme.com.
5. Move the SDK separately
Importing links does not touch your app. Links route by device and open the app through the deep link on every paid plan without any SDK. Universal Links and App Links follow the domain, so once a domain points to Appy, iOS and Android read the association files from Appy.
- On Enterprise, register the app under Apps & SDK and assign the domain to it, so Appy serves
apple-app-site-associationandassetlinks.jsonon it (app links on your domain). - Replace the AppsFlyer SDK’s deep linking calls with the Appy SDK for iOS or Android, or use two HTTP calls from React Native, Flutter or Unity.
deep_link_valuenow arrives as a query parameter of the deep link URL. - Ship the app update before or together with the DNS change, so new installs and returning users land in the app.
Import with the API
Send the file’s contents as csv. Run with "dryRun": true first: the response is the same report the dashboard shows and nothing is written. Send the same request with "dryRun": false to create the ready links. The API reference has the full schema.
curl https://api.appy.to/v1/links/import \
-H "Authorization: Bearer $APPY_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"source": "onelink",
"dryRun": true,
"csv": "Short link,af_web_dp,af_ios_url,af_android_url,c\nhttps://click.acme.com/A1bc/spring,https://acme.com/spring,https://apps.apple.com/app/id123456789,https://play.google.com/store/apps/details?id=com.acme.shop,spring\n",
"defaults": {"deeplinkScheme": "acme://"}
}'{
"dryRun": true,
"source": "onelink",
"plan": "business",
"limit": 500,
"used": 37,
"summary": {
"rows": 1,
"ready": 1,
"imported": 0,
"existing": 0,
"errors": 0,
"overLimit": 0,
"aliasesKept": 0,
"aliasesChanged": 1,
"withWarnings": 1
},
"domains": [
{
"host": "click.acme.com",
"kind": "branded",
"rows": 1,
"appyStatus": "not_added"
}
],
"rows": [
{
"line": 2,
"status": "ready",
"alias": "spring",
"slug": "spring",
"aliasKept": false,
"fallbackUrl": "https://acme.com/spring?utm_campaign=spring",
"targets": {
"iphone": "https://apps.apple.com/app/id123456789",
"android": "https://play.google.com/store/apps/details?id=com.acme.shop"
},
"unsupported": [],
"ignored": [],
"issues": [
{
"code": "alias_path_segments",
"severity": "warning",
"field": "slug",
"message": "The old link path /A1bc/spring has more than one part. The new link is /spring, so printed links with the old path do not carry over."
}
]
}
]
}statusisready(dry run only),imported,exists,errororover_limit.aliasKeptistruewhen the old path equals the new one, so the old URL works once its domain points to Appy.issuescarry a stablecode, aseverityand an Englishmessage;unsupportedandignoredlist the keys of that row that did not move.- Rate limits and errors are the same as for the other link endpoints.
Limits
onelink.melinks cannot move; only branded domains can.- Two-part OneLink paths become one-part Appy paths, so printed codes with the old path need a new QR code even on a branded domain.
- One deep link per link. Attribution parameters such as ad sets, sub parameters and lookback windows are not stored on the link.
- Up to 1000 links per file. Larger exports go in several files; links already imported are skipped, so files can overlap.
- Imports count toward your plan’s link limit like any other link; rows that do not fit are reported, not dropped.
- Moving the SDK, attribution history and AppsFlyer integrations is a separate step.