Get Embeddable Bio Page
Iframe-friendly variant of the public bio render — same payload, but only succeeds when embedEnabled is true. Sets X-Frame-Options ALLOWALL so partner sites can host the iframe.
GET /api/v1/bio/embed/:username — 🌐 Public · Rate limit: 120 req / minute
Same payload as GET /bio/:username, gated by BioPage.embedEnabled === true. Sets X-Frame-Options: ALLOWALL so the response can be rendered inside third-party <iframe> tags. CDN-cached s-maxage=60, stale-while-revalidate=300 (same as the public render).
Embed is opt-in per creator. Creators flip embedEnabled via PATCH /creators/:creatorId/bio { embedEnabled: true }. When false, this endpoint returns 403 creator.bio.embed_disabled even if the underlying bio page is otherwise public via GET /bio/:username.
X-Frame-Options: ALLOWALL is intentional. The whole purpose of this endpoint is iframe embedding. The non-embed render (GET /bio/:username) does not set this header, so it inherits the platform default (clickjacking-protected). Use the right endpoint for the right context.
Request
Path parameters
| Param | Type | Notes |
|---|---|---|
username | string | Lowercased server-side; case-insensitive lookup |
No body, no headers required.
Response headers
| Header | Value |
|---|---|
Cache-Control | public, s-maxage=60, stale-while-revalidate=300 |
X-Frame-Options | ALLOWALL |
Response
200 OK — ApiResponseOf<PublicBioPageResponseDto>
Same shape as GET /bio/:username. See Get Public Bio Page for the full field reference.
Errors
| HTTP | code / i18nKey | Reason |
|---|---|---|
403 | creator.bio.embed_disabled | BioPage.embedEnabled === false |
404 | creator.bio.not_found | Same status filter as the public render: user / creator / published checks fail |
429 | (throttle) | Rate limit exceeded (120 req/min) |
Side effects
- Cache hit / miss path — identical to
GET /bio/:username. Reuses the samegetCachedBioPage()payload (no separate cache key). - After resolution, assert
bioPage.embedEnabled === true. If not → throwembed_disabled(403). - Return the cached / freshly built payload.
Code samples
curl https://api.bio.re/api/v1/bio/embed/johndoe<!-- Embed a creator's bio page in your site -->
<iframe
src="https://bio.re/embed/johndoe"
width="400"
height="600"
frameborder="0"
loading="lazy"
></iframe>async function getEmbedBioPage(username: string): Promise<unknown> {
const res = await fetch(`https://api.bio.re/api/v1/bio/embed/${encodeURIComponent(username)}`);
if (res.status === 403) {
throw new Error('Embedding is not enabled for this bio page');
}
if (res.status === 404) return null;
const json = await res.json();
if (!res.ok || !json.success) {
throw Object.assign(new Error(json?.error?.message ?? 'Embed fetch failed'), {
code: json?.error?.code,
});
}
return json.data;
}Try it
Path Parameters
Response Body
application/json
application/json
application/json
application/json
curl -X GET "https://loading/api/v1/bio/embed/string"{
"success": true,
"data": {
"userId": "2c4a230c-5085-4924-a3e1-25fb4fc5965b",
"username": "johndoe",
"displayName": "John Doe",
"bio": "string",
"avatarUrl": "https://cdn.bio.re/avatars/abc.jpg",
"level": "BRONZE",
"dmType": "FREE",
"dmPrice": "5.00",
"dmActive": true,
"vacationMode": false,
"avgRating": "4.5",
"ratingCount": 42,
"userStatus": "ACTIVE",
"bioPage": {
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
"bio": "string",
"templateId": "196100ac-4eec-4fb6-a7f7-86c8b584771d",
"themeOverride": {},
"customCss": "string",
"embedEnabled": false,
"published": true,
"emailCollectionEnabled": false,
"links": [
{
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
"title": "My Website",
"url": "https://example.com",
"icon": "string",
"isSocial": false,
"platform": "YOUTUBE",
"embedType": "VIDEO",
"embedMeta": {}
}
],
"template": {
"name": "Minimal Dark",
"tokens": {}
}
},
"socialAccounts": [
{
"platform": "INSTAGRAM",
"platformUsername": "johndoe"
}
],
"dmPackages": [
{
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
"dmType": "FREE",
"price": "5.00"
}
],
"themePreset": {
"slug": "midnight",
"name": "Midnight",
"lightTokens": {},
"darkTokens": {},
"typography": {},
"layout": {}
},
"referralBadge": {
"enabled": true,
"referralCode": "ABC123",
"url": "https://bio.re/r/ABC123"
}
}
}{
"success": false,
"error": {
"code": "AUTH_UNAUTHORIZED",
"message": "Invalid credentials",
"i18nKey": "auth.login.invalid_credentials",
"i18nVars": {
"field": "email"
},
"details": [
{
"message": "email must be an email"
}
],
"correlationId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}
}{
"success": false,
"error": {
"code": "AUTH_UNAUTHORIZED",
"message": "Invalid credentials",
"i18nKey": "auth.login.invalid_credentials",
"i18nVars": {
"field": "email"
},
"details": [
{
"message": "email must be an email"
}
],
"correlationId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}
}{
"success": false,
"error": {
"code": "AUTH_UNAUTHORIZED",
"message": "Invalid credentials",
"i18nKey": "auth.login.invalid_credentials",
"i18nVars": {
"field": "email"
},
"details": [
{
"message": "email must be an email"
}
],
"correlationId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}
}Source
| Source | Path | Lines |
|---|---|---|
| Controller | apps/api-core/src/modules/creator/bio-analytics.controller.ts | 26–43 (getEmbedBioPage) |
| DTO (response) | apps/api-core/src/modules/creator/dto/bio-analytics-response.dto.ts | 152–206 (PublicBioPageResponseDto) |
| Service | apps/api-core/src/modules/creator/bio-analytics.service.ts | 52–158 (getCachedBioPage — shared with GET /bio/:username) |
| Prisma model | packages/prisma/prisma/schema.prisma | BioPage.embedEnabled |
Reorder Bio Links
Atomic reordering of bio page links. Submit the full ordered array; sortOrder is set to the array index. Server verifies every linkId belongs to the creator before writing.
Track Bio Page View
Append a view record. Server parses User-Agent and resolves country from CDN headers when the client doesn't supply them. Creator-side analytics aggregate from this stream.