Skip to main content

Exporting Links (CSV)

Export every link in a project — together with its click and install analytics — to a CSV file. Exports are a paid-plan feature and run as a background job, so a large project never blocks your browser. When the file is ready you get an email and a download link.

Exporting from the dashboard

There are two places to start an export:

From the Links page (filtered export)

  1. Go to Dashboard → Links.
  2. (Optional) Apply a search or a date range. The date range on this page is an activity window: the list shows every link with its clicks and installs counted inside that range, and the export uses exactly the same window, so the CSV matches the numbers on screen.
  3. Click Export CSV.

From the Analytics overview (time-range export)

  1. Go to Dashboard → Links → Analytics.
  2. Pick a time range (24 Hours, 7 Days, 30 Days or All Time). The headline numbers and the list update to that window.
  3. Click Export CSV. Every link in the project is exported with its Clicks, New Installs, Returning Users and the top-X / attributed columns counted inside the selected window, and the window is stamped in the Period Start / Period End columns. With All Time those two columns are empty and the numbers are lifetime totals.

The job starts immediately. You can keep working; when it finishes you'll receive an "export ready" email with a download link, and the download also appears in the dashboard.

What's in the file

One row per link, with these columns:

ColumnDescription
NameThe link's name
Typedynamic or unified
SlugThe link's slug
Short URLThe full short link
Created AtWhen the link was created
ClicksTotal clicks
New InstallsInstalls attributed to the link
Returning UsersReturning-user opens attributed to the link
Attributed ClicksClicks matched to an install/open
Top DeviceMost common device
Top OSMost common operating system
Top BrowserMost common browser
Top CountryMost common country
Last Clicked AtTimestamp of the most recent click
Period StartStart of the activity window the numbers were counted in (empty = lifetime)
Period EndEnd of the activity window (empty = lifetime)

Limits

  • 100,000 links per export. If a project (after filters) exceeds this, the job fails with a message asking you to narrow the filters — split the export by date range to stay under the cap.
  • Download links are signed and valid for 7 days. Re-open the export from the dashboard to mint a fresh link after that.

How it works (API)

The dashboard drives two endpoints. They authenticate with a dashboard (Supabase) session — these are not API-key endpoints, and an export cannot be triggered with an SDK API key.

Start an export

POST https://api.ulink.ly/api/v1/projects/{projectId}/links/export
Authorization: Bearer <supabase-session-jwt>
Content-Type: application/json

{
"search": "summer",
"createdAfter": "2026-01-01",
"createdBefore": "2026-06-30",
"sortBy": "createdAt",
"sortOrder": "desc"
}

All body fields are optional and mirror the filters on the Links page.

To export with an activity window instead (what the dashboard's Links page and Analytics overview do), send activeAfter / activeBefore ISO timestamps. The click and install columns are then counted inside that window, and every link in the project is included whether or not it had activity. createdAfter / createdBefore still apply on top of the window if you send both, so "links created in May, with their June clicks" is one request. An open-ended bound is fine; if the two bounds are reversed they are swapped. Note that the 100,000-row cap counts links, not clicks, so a narrower window does not reduce the row count; use a creation-date range or a search to get under the cap:

{
"activeAfter": "2026-09-03T12:00:00.000Z",
"activeBefore": "2026-09-10T12:00:00.000Z",
"sortBy": "clickCount",
"sortOrder": "desc"
}

The response returns a job to poll:

{ "success": true, "data": { "jobId": "…", "status": "pending" } }

Poll for the result

GET https://api.ulink.ly/api/v1/projects/{projectId}/links/export/{jobId}
Authorization: Bearer <supabase-session-jwt>
{
"success": true,
"data": {
"status": "completed",
"rowCount": 1280,
"error": null,
"downloadUrl": "https://…signed-url…"
}
}

status moves through pending → processing → completed (or failed, with the reason in error). A fresh signed downloadUrl is minted on each read of a completed job, so you can always poll again for a new link rather than caching the URL.

Free plans receive 402 Payment Required from the start endpoint.