Websites
Website Library endpoints expose public-safe domain and landing page summaries through the /v1 API. These routes return stable metrics, technology slugs, offer and quality fields, timestamps, favicon URLs, counts, linked page previews, and appUrl links for opening records in the AfterLib web app. Raw analysis payloads, crawl state, and scrape internals are not included.
Website Library routes are no-credit in this phase.
Search domains
Section titled “Search domains”| Parameter | Location | Type | Default | Allowed values | Description |
|---|---|---|---|---|---|
limit | query | number | 50 | 1 to 100 | Maximum domains returned. |
offset | query | number | 0 | 0 or higher | Offset for page-style pagination. |
search | query | string | none | up to 255 chars | Match domain text. |
sortBy | query | string | activeAds30d | domain, activeAds30d, activeLinks30d, firstSeenAt, swGlobalRank, lastSeenAt, technologySlugs | Sort field. |
sortDirection | query | string | desc | asc, desc | Sort direction. |
curl "https://api.afterlib.com/v1/websites/domains?limit=25&search=example&sortBy=activeAds30d&sortDirection=desc" \ -H "Authorization: Bearer $AFTERLIB_API_KEY"const url = new URL('https://api.afterlib.com/v1/websites/domains');url.search = new URLSearchParams({ limit: '25', search: 'example', sortBy: 'activeAds30d', sortDirection: 'desc',}).toString();
const response = await fetch(url, { headers: {Authorization: `Bearer ${process.env.AFTERLIB_API_KEY}`},});
const domains = await response.json();type WebsiteDomainSearchRequest = { limit?: number; offset?: number; search?: string; sortBy?: 'domain' | 'activeAds30d' | 'activeLinks30d' | 'firstSeenAt' | 'swGlobalRank' | 'lastSeenAt' | 'technologySlugs'; sortDirection?: 'asc' | 'desc';};
const request: WebsiteDomainSearchRequest = { limit: 25, search: 'example', sortBy: 'activeAds30d', sortDirection: 'desc',};
const url = new URL('https://api.afterlib.com/v1/websites/domains');url.search = new URLSearchParams( Object.entries(request).map(([key, value]) => [key, String(value)]),).toString();
const response = await fetch(url, { headers: {Authorization: 'Bearer ' + process.env.AFTERLIB_API_KEY},});
const domains = await response.json();$query = http_build_query([ 'limit' => 25, 'search' => 'example', 'sortBy' => 'activeAds30d', 'sortDirection' => 'desc',]);
$response = file_get_contents("https://api.afterlib.com/v1/websites/domains?$query", false, stream_context_create([ 'http' => [ 'header' => 'Authorization: Bearer ' . getenv('AFTERLIB_API_KEY'), ],]));
$domains = json_decode($response, true);import jsonimport osimport urllib.parseimport urllib.request
query = urllib.parse.urlencode({ 'limit': 25, 'search': 'example', 'sortBy': 'activeAds30d', 'sortDirection': 'desc',})
request = urllib.request.Request( f'https://api.afterlib.com/v1/websites/domains?{query}', headers={'Authorization': f"Bearer {os.environ['AFTERLIB_API_KEY']}"},)
with urllib.request.urlopen(request) as response: domains = json.loads(response.read().decode('utf-8'))Response:
{ "items": [ { "id": "019e6387-e2e9-7478-9d6d-170158c523b1", "domain": "seed-store.afterlib.local", "appUrl": "https://app.afterlib.com/websites/domain/019e6387-e2e9-7478-9d6d-170158c523b1", "technologySlugs": ["shopify", "klaviyo"], "categories": ["beauty"], "swGlobalRank": 12450, "swGlobalTraffic": 1200000, "activeAds30d": 42, "activeLinks30d": 8, "activePages30d": 3, "firstSeenAt": "2025-08-26T09:04:49.640Z", "lastSeenAt": "2025-09-03T09:04:49.640Z", "linkedPages": [ { "metaPageExternalId": "9000000000500", "pageName": "Drift Wellness Company", "linkedAdsCount": 12 } ] } ], "pageInfo": {"limit": 50, "offset": 0, "total": 1, "hasMore": false}}Search links
Section titled “Search links”| Parameter | Location | Type | Default | Allowed values | Description |
|---|---|---|---|---|---|
domainId | query | UUID string | none | Website Library domain ID | Limit links to one domain. |
limit | query | number | 50 | 1 to 100 | Maximum links returned. |
offset | query | number | 0 | 0 or higher | Offset for page-style pagination. |
search | query | string | none | up to 255 chars | Match link or domain text. |
sortBy | query | string | activeAds30d | domain, linkPath, activeAds30d, activeAdsChangePercent30d, firstSeenAt, percentOfDomainAds30d, lastSeenAt, technologySlugs | Sort field. |
sortDirection | query | string | desc | asc, desc | Sort direction. |
curl "https://api.afterlib.com/v1/websites/links?limit=25&search=product&sortBy=activeAds30d&sortDirection=desc" \ -H "Authorization: Bearer $AFTERLIB_API_KEY"const url = new URL('https://api.afterlib.com/v1/websites/links');url.search = new URLSearchParams({ limit: '25', search: 'product', sortBy: 'activeAds30d', sortDirection: 'desc',}).toString();
const response = await fetch(url, { headers: {Authorization: `Bearer ${process.env.AFTERLIB_API_KEY}`},});
const links = await response.json();type WebsiteLinkSearchRequest = { domainId?: string; limit?: number; offset?: number; search?: string; sortBy?: 'domain' | 'linkPath' | 'activeAds30d' | 'activeAdsChangePercent30d' | 'firstSeenAt' | 'percentOfDomainAds30d' | 'lastSeenAt' | 'technologySlugs'; sortDirection?: 'asc' | 'desc';};
const request: WebsiteLinkSearchRequest = { limit: 25, search: 'product', sortBy: 'activeAds30d', sortDirection: 'desc',};
const url = new URL('https://api.afterlib.com/v1/websites/links');url.search = new URLSearchParams( Object.entries(request).map(([key, value]) => [key, String(value)]),).toString();
const response = await fetch(url, { headers: {Authorization: 'Bearer ' + process.env.AFTERLIB_API_KEY},});
const links = await response.json();$query = http_build_query([ 'limit' => 25, 'search' => 'product', 'sortBy' => 'activeAds30d', 'sortDirection' => 'desc',]);
$response = file_get_contents("https://api.afterlib.com/v1/websites/links?$query", false, stream_context_create([ 'http' => [ 'header' => 'Authorization: Bearer ' . getenv('AFTERLIB_API_KEY'), ],]));
$links = json_decode($response, true);import jsonimport osimport urllib.parseimport urllib.request
query = urllib.parse.urlencode({ 'limit': 25, 'search': 'product', 'sortBy': 'activeAds30d', 'sortDirection': 'desc',})
request = urllib.request.Request( f'https://api.afterlib.com/v1/websites/links?{query}', headers={'Authorization': f"Bearer {os.environ['AFTERLIB_API_KEY']}"},)
with urllib.request.urlopen(request) as response: links = json.loads(response.read().decode('utf-8'))Response:
{ "items": [ { "id": "019e6387-e2e9-7478-9d6d-170158c523b2", "domainId": "019e6387-e2e9-7478-9d6d-170158c523b1", "domain": "seed-store.afterlib.local", "appUrl": "https://app.afterlib.com/websites/019e6387-e2e9-7478-9d6d-170158c523b2", "linkPath": "/products/routine", "themeText": "daily routine landing page", "technologySlugs": ["shopify", "klaviyo"], "activeAds30d": 18, "percentOfDomainAds30d": 42.86, "pageType": "product", "hasDiscount": true, "offerType": "percentage", "offerValue": "20%", "pageQuality": "high", "generalSummary": "Public landing page summary for competitive research." } ], "pageInfo": {"limit": 50, "offset": 0, "total": 1, "hasMore": false}}Related pages and ads
Section titled “Related pages and ads”Use related routes to move from a domain or landing page to the public pages and ads connected to it.
| Parameter | Location | Type | Default | Allowed values | Description |
|---|---|---|---|---|---|
limit | query | number | 50 | 1 to 100 | Maximum related records returned. |
offset | query | number | 0 | 0 or higher | Offset for page-style pagination. |
search | query | string | none | up to 255 chars | Optional text filter for related pages or ads. |
curl "https://api.afterlib.com/v1/websites/domains/019e6387-e2e9-7478-9d6d-170158c523b1/pages?limit=25&offset=0" \ -H "Authorization: Bearer $AFTERLIB_API_KEY"const response = await fetch( 'https://api.afterlib.com/v1/websites/domains/019e6387-e2e9-7478-9d6d-170158c523b1/pages?limit=25&offset=0', {headers: {Authorization: `Bearer ${process.env.AFTERLIB_API_KEY}`}},);
const pages = await response.json();type RelatedDomainPagesRequest = { domainId: string; limit?: number; offset?: number; search?: string;};
const request: RelatedDomainPagesRequest = { domainId: '019e6387-e2e9-7478-9d6d-170158c523b1', limit: 25, offset: 0,};
const params = new URLSearchParams({ limit: String(request.limit), offset: String(request.offset),});
const response = await fetch( 'https://api.afterlib.com/v1/websites/domains/019e6387-e2e9-7478-9d6d-170158c523b1/pages?' + params, {headers: {Authorization: 'Bearer ' + process.env.AFTERLIB_API_KEY}},);
const pages = await response.json();$response = file_get_contents('https://api.afterlib.com/v1/websites/domains/019e6387-e2e9-7478-9d6d-170158c523b1/pages?limit=25&offset=0', false, stream_context_create([ 'http' => [ 'header' => 'Authorization: Bearer ' . getenv('AFTERLIB_API_KEY'), ],]));
$pages = json_decode($response, true);import jsonimport osimport urllib.request
request = urllib.request.Request( 'https://api.afterlib.com/v1/websites/domains/019e6387-e2e9-7478-9d6d-170158c523b1/pages?limit=25&offset=0', headers={'Authorization': f"Bearer {os.environ['AFTERLIB_API_KEY']}"},)
with urllib.request.urlopen(request) as response: pages = json.loads(response.read().decode('utf-8'))Related pages from a landing page:
curl "https://api.afterlib.com/v1/websites/links/019e6387-e2e9-7478-9d6d-170158c523b2/pages?limit=25" \ -H "Authorization: Bearer $AFTERLIB_API_KEY"const response = await fetch( 'https://api.afterlib.com/v1/websites/links/019e6387-e2e9-7478-9d6d-170158c523b2/pages?limit=25', {headers: {Authorization: `Bearer ${process.env.AFTERLIB_API_KEY}`}},);
const pages = await response.json();type RelatedLinkPagesRequest = { linkId: string; limit?: number; offset?: number; search?: string;};
const request: RelatedLinkPagesRequest = { linkId: '019e6387-e2e9-7478-9d6d-170158c523b2', limit: 25,};
const params = new URLSearchParams({limit: String(request.limit)});
const response = await fetch( 'https://api.afterlib.com/v1/websites/links/019e6387-e2e9-7478-9d6d-170158c523b2/pages?' + params, {headers: {Authorization: 'Bearer ' + process.env.AFTERLIB_API_KEY}},);
const pages = await response.json();$response = file_get_contents('https://api.afterlib.com/v1/websites/links/019e6387-e2e9-7478-9d6d-170158c523b2/pages?limit=25', false, stream_context_create([ 'http' => [ 'header' => 'Authorization: Bearer ' . getenv('AFTERLIB_API_KEY'), ],]));
$pages = json_decode($response, true);import jsonimport osimport urllib.request
request = urllib.request.Request( 'https://api.afterlib.com/v1/websites/links/019e6387-e2e9-7478-9d6d-170158c523b2/pages?limit=25', headers={'Authorization': f"Bearer {os.environ['AFTERLIB_API_KEY']}"},)
with urllib.request.urlopen(request) as response: pages = json.loads(response.read().decode('utf-8'))Related ads from a landing page:
curl "https://api.afterlib.com/v1/websites/links/019e6387-e2e9-7478-9d6d-170158c523b2/ads?limit=25" \ -H "Authorization: Bearer $AFTERLIB_API_KEY"const response = await fetch( 'https://api.afterlib.com/v1/websites/links/019e6387-e2e9-7478-9d6d-170158c523b2/ads?limit=25', {headers: {Authorization: `Bearer ${process.env.AFTERLIB_API_KEY}`}},);
const ads = await response.json();type RelatedLinkAdsRequest = { linkId: string; limit?: number; offset?: number; search?: string;};
const request: RelatedLinkAdsRequest = { linkId: '019e6387-e2e9-7478-9d6d-170158c523b2', limit: 25,};
const params = new URLSearchParams({limit: String(request.limit)});
const response = await fetch( 'https://api.afterlib.com/v1/websites/links/019e6387-e2e9-7478-9d6d-170158c523b2/ads?' + params, {headers: {Authorization: 'Bearer ' + process.env.AFTERLIB_API_KEY}},);
const ads = await response.json();$response = file_get_contents('https://api.afterlib.com/v1/websites/links/019e6387-e2e9-7478-9d6d-170158c523b2/ads?limit=25', false, stream_context_create([ 'http' => [ 'header' => 'Authorization: Bearer ' . getenv('AFTERLIB_API_KEY'), ],]));
$ads = json_decode($response, true);import jsonimport osimport urllib.request
request = urllib.request.Request( 'https://api.afterlib.com/v1/websites/links/019e6387-e2e9-7478-9d6d-170158c523b2/ads?limit=25', headers={'Authorization': f"Bearer {os.environ['AFTERLIB_API_KEY']}"},)
with urllib.request.urlopen(request) as response: ads = json.loads(response.read().decode('utf-8'))These related routes are also no-credit in this phase.