Appy

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

ExportWhereWhat it contains
OneLink links CSVEngage > OneLink Management, choose the template, then ExportLinks 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 CSVThe file you uploaded under Engage > Bulk linksCustom 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 v2GET /api/v2.0/shortlinks/{onelink-id}/{shortlink-id}, one link per callThe 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 parameterIn Appy
af_web_dpWebsite: where computers and devices without a target go
af_rWebsite 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_urliPhone target. iPads use it too.
af_android_urlAndroid target
af_dpDeep link (Pro and above)
deep_link_value, deep_link_sub1 to deep_link_sub10Query 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, cutm_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_titleLink title in the dashboard
af_og_title, af_og_description, af_og_imageSocial 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 IDThe 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_sub1 to af_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_dp or deep_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. 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. 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. 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. 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.

Your branded domainonelink.me domainOneLink pathclick.acme.com/A1bc/springImported asclick.acme.com/springNew QR codereprint printed codesacme.onelink.me/A1bc/…shared earlierStays at AppsFlyercannot point to AppyNew Appy linkshare or reprint
OneLink paths have two parts and Appy paths have one, so the short link ID becomes the path and printed codes with the old path need a new QR code.

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 linkWhat happens
On your branded domain, such as click.acme.com/A1bc/springThe 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/springThis 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 takenThe 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-association and assetlinks.json on 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_value now 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.

bash
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://"}
  }'
response (shortened)
{
  "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."
        }
      ]
    }
  ]
}
  • status is ready (dry run only), imported, exists, error or over_limit.
  • aliasKept is true when the old path equals the new one, so the old URL works once its domain points to Appy.
  • issues carry a stable code, a severity and an English message; unsupported and ignored list the keys of that row that did not move.
  • Rate limits and errors are the same as for the other link endpoints.

Limits

  • onelink.me links 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.