Skip to Content
Elido is in closed beta — APIs are stable but rate-limits and quotas may change before GA. Request access →
GuidesBio pages

Bio pages

A bio page is a single mobile-first landing page hosting a stack of links — the format Linktree popularised for “link in bio” on Instagram, TikTok, and X. Each page lives at bio.elido.app/<username> (or a custom domain) and is rendered server-side by bio-renderer so it loads on the first paint.

Bio pages are independent from short links: they have their own URL namespace, their own click stream, and their own analytics.

Create a page

curl -X POST \ https://api.elido.app/v1/workspaces/1/bio \ -H "Authorization: Bearer $ELIDO_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "username": "acme", "display_name": "Acme Inc.", "bio": "We make sprockets that just work.", "avatar_url": "https://cdn.example.com/avatar.png", "is_published": true, "theme": { "bg_color": "#0f172a", "text_color": "#f8fafc", "button_style": "rounded", "button_color": "#5b6cff", "button_radius": 12 } }'
FieldNotes
username3–32 chars, lowercase letters, digits, -, _. Globally unique.
display_nameBold name shown above the bio.
bioFree text below the name.
avatar_urlOptional image URL; rendered as a circle.
is_publishedDefaults false. Unpublished pages 404 publicly.
themeJSON with bg_color, text_color, button_style, button_color, button_radius.
curl -X POST \ https://api.elido.app/v1/workspaces/1/bio/9/links \ -H "Authorization: Bearer $ELIDO_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "title": "Latest blog post", "url": "https://example.com/blog/sprocket-3", "icon": "rss", "sort_order": 0 }'

sort_order controls render order ascending; rebalance with PATCH on each link or rely on the dashboard’s drag-and-drop. Icons are Lucide names (rss, youtube, instagram, …).

Public render

The page itself comes from the bio-renderer service:

GET https://bio.elido.app/acme

The renderer fetches GET /v1/bio/acme (public, unauthenticated) once per request and caches by username for 60 seconds.

Click tracking

Each button has a fire-and-forget tracker:

navigator.sendBeacon( "https://api.elido.app/v1/bio/acme/click", JSON.stringify({ link_id: 17 }) );

The renderer wires this up automatically — you don’t ship the JavaScript yourself. The endpoint records Country, User-Agent, and Referer, then fans out to ClickHouse via the same click-ingester pipeline as short-link clicks.

Heatmap

Per-link click totals power the dashboard heatmap:

curl https://api.elido.app/v1/workspaces/1/bio/9/heatmap \ -H "Authorization: Bearer $ELIDO_TOKEN"
[ { "bio_link_id": 17, "clicks": 4321 }, { "bio_link_id": 18, "clicks": 1187 } ]

The dashboard renders this as a horizontal bar chart sorted by sort_order so you can see at a glance which links are pulling weight and which are dead.

Endpoint reference

MethodPath
GET/v1/workspaces/{ws}/bio (list)
POST/v1/workspaces/{ws}/bio (create page)
PATCH/v1/workspaces/{ws}/bio/{id}
DELETE/v1/workspaces/{ws}/bio/{id}
GET/v1/workspaces/{ws}/bio/{id}/links
POST/v1/workspaces/{ws}/bio/{id}/links
PATCH/v1/workspaces/{ws}/bio/{id}/links/{link_id}
DELETE/v1/workspaces/{ws}/bio/{id}/links/{link_id}
GET/v1/workspaces/{ws}/bio/{id}/heatmap
GET/v1/bio/{username} (public render)
POST/v1/bio/{username}/click (public click)