# Websites

export const domainsCurl = `curl "https://api.afterlib.com/v1/websites/domains?limit=25&search=example&sortBy=activeAds30d&sortDirection=desc" \\
  -H "Authorization: Bearer $AFTERLIB_API_KEY"`;

export const domainsJs = `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();`;

export const domainsTs = `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();`;

export const domainsPhp = `$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);`;

export const domainsPython = `import json
import os
import urllib.parse
import 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'))`;

export const linksCurl = `curl "https://api.afterlib.com/v1/websites/links?limit=25&search=product&sortBy=activeAds30d&sortDirection=desc" \\
  -H "Authorization: Bearer $AFTERLIB_API_KEY"`;

export const linksJs = `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();`;

export const linksTs = `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();`;

export const linksPhp = `$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);`;

export const linksPython = `import json
import os
import urllib.parse
import 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'))`;

export const relatedPagesCurl = `curl "https://api.afterlib.com/v1/websites/domains/019e6387-e2e9-7478-9d6d-170158c523b1/pages?limit=25&offset=0" \\
  -H "Authorization: Bearer $AFTERLIB_API_KEY"`;

export const relatedPagesJs = `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();`;

export const relatedPagesTs = `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();`;

export const relatedPagesPhp = `$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);`;

export const relatedPagesPython = `import json
import os
import 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'))`;

export const relatedLinkPagesCurl = `curl "https://api.afterlib.com/v1/websites/links/019e6387-e2e9-7478-9d6d-170158c523b2/pages?limit=25" \\
  -H "Authorization: Bearer $AFTERLIB_API_KEY"`;

export const relatedLinkPagesJs = `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();`;

export const relatedLinkPagesTs = `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();`;

export const relatedLinkPagesPhp = `$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);`;

export const relatedLinkPagesPython = `import json
import os
import 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'))`;

export const relatedLinkAdsCurl = `curl "https://api.afterlib.com/v1/websites/links/019e6387-e2e9-7478-9d6d-170158c523b2/ads?limit=25" \\
  -H "Authorization: Bearer $AFTERLIB_API_KEY"`;

export const relatedLinkAdsJs = `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();`;

export const relatedLinkAdsTs = `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();`;

export const relatedLinkAdsPhp = `$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);`;

export const relatedLinkAdsPython = `import json
import os
import 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'))`;

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

| 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. |

<ApiExampleTabs curl={domainsCurl} javascript={domainsJs} typescript={domainsTs} php={domainsPhp} python={domainsPython} />

Response:

```json
{
	"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

| 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. |

<ApiExampleTabs curl={linksCurl} javascript={linksJs} typescript={linksTs} php={linksPhp} python={linksPython} />

Response:

```json
{
	"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

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. |

<ApiExampleTabs curl={relatedPagesCurl} javascript={relatedPagesJs} typescript={relatedPagesTs} php={relatedPagesPhp} python={relatedPagesPython} />

Related pages from a landing page:

<ApiExampleTabs curl={relatedLinkPagesCurl} javascript={relatedLinkPagesJs} typescript={relatedLinkPagesTs} php={relatedLinkPagesPhp} python={relatedLinkPagesPython} />

Related ads from a landing page:

<ApiExampleTabs curl={relatedLinkAdsCurl} javascript={relatedLinkAdsJs} typescript={relatedLinkAdsTs} php={relatedLinkAdsPhp} python={relatedLinkAdsPython} />

These related routes are also no-credit in this phase.