Notion URLs identify pages, databases, and blocks with unique IDs. Understanding these URL patterns is essential for building integrations and automations.
Key Takeaways
- 1Notion page IDs are 32-character UUIDs without dashes
- 2URLs contain page title slug for readability
- 3Database views have unique URLs with view parameters
- 4API uses dashed UUID format (8-4-4-4-12)
- 5Block IDs identify individual content blocks
“The Notion API allows you to connect your Notion workspace to other tools and build your own integrations.”
URL Structure
Notion URLs combine human-readable page titles with unique identifiers. This hybrid approach provides both usability for humans sharing links and reliability for programmatic access.
| Type | Pattern | Example |
|---|---|---|
| Page | /workspace/Page-Title-{id} | /workspace/My-Page-abc123 |
| Database | /workspace/{id}?v={view_id} | /workspace/abc123?v=def456 |
| Public page | /{workspace}.notion.site/{slug}-{id} | /myco.notion.site/Page-abc |
| Block anchor | /Page-{id}#{block_id} | /Page-abc123#block-def456 |
The table shows how URL patterns differ between internal workspace pages, public pages, and database views. Block anchors let you link directly to specific content within a page, which is useful for documentation or when referencing particular sections.
Page URLs include both a slug (derived from the page title) and a unique ID. The slug makes URLs readable but can change if you rename pages. The ID at the end is what Notion actually uses to locate the page.
Page URLs
# Notion page URL structure
https://www.notion.so/{workspace}/{Page-Title}-{page_id}
# Example
https://www.notion.so/myworkspace/Project-Roadmap-abc123def456789
# Page ID extraction
# URL: /myworkspace/Project-Roadmap-abc123def456789
# Page ID: abc123def456789 (last segment after final hyphen)
# With view parameters (for database pages)
https://www.notion.so/myworkspace/Tasks-abc123?v=def456&p=ghi789
# Query parameters:
# v = view ID (for database views)
# p = property ID (for filtering)
# pvs = property visibility settings
# Block anchor
https://www.notion.so/myworkspace/Page-abc123#block-def456
# The #block-def456 links to a specific block within the pageQuery parameters on database URLs control which view is displayed and can include filtering options. The v parameter specifies the view ID when a database has multiple views. Block anchors use a hash followed by block- and the block's ID without dashes.
Notion uses two different ID formats: URLs contain 32-character IDs without dashes, while the API requires UUID format with dashes. Converting between these formats is essential when building integrations.
ID Format Conversion
// Notion IDs: URL format vs API format
// URL format: 32 characters, no dashes
const urlId = 'abc123def456789012345678901234ab';
// API format: UUID with dashes (8-4-4-4-12)
const apiId = 'abc123de-f456-7890-1234-5678901234ab';
// Convert URL ID to API ID
function toApiId(urlId) {
const clean = urlId.replace(/-/g, '');
return [
clean.slice(0, 8),
clean.slice(8, 12),
clean.slice(12, 16),
clean.slice(16, 20),
clean.slice(20, 32)
].join('-');
}
// Convert API ID to URL ID
function toUrlId(apiId) {
return apiId.replace(/-/g, '');
}
// Extract page ID from URL
function extractPageId(url) {
const urlObj = new URL(url);
const path = urlObj.pathname;
// Get last segment
const segments = path.split('/').filter(Boolean);
const lastSegment = segments[segments.length - 1];
// Extract ID (last 32 chars or after last hyphen)
const match = lastSegment.match(/([a-f0-9]{32})$/i);
if (match) {
return toApiId(match[1]);
}
// Handle hyphenated format
const parts = lastSegment.split('-');
const idPart = parts[parts.length - 1];
if (idPart.length === 32) {
return toApiId(idPart);
}
return null;
}
// Usage
const pageId = extractPageId('https://www.notion.so/workspace/My-Page-abc123def456789012345678901234ab');
console.log(pageId); // abc123de-f456-7890-1234-5678901234abThe conversion functions handle the dash insertion and removal. The extractPageId function parses a full Notion URL to get the page ID in API format. Note that the ID appears after the last hyphen in the URL's final path segment, which can be confusing since hyphens also separate words in the slug.
The Notion API provides programmatic access to pages, databases, blocks, and users. All endpoints require authentication via a Bearer token and the Notion-Version header for API compatibility.
API Endpoints
// Notion API base URL
const baseUrl = 'https://api.notion.com/v1';
// Common endpoints
const endpoints = {
// Pages
getPage: '/pages/{page_id}',
createPage: '/pages',
updatePage: '/pages/{page_id}',
// Databases
getDatabase: '/databases/{database_id}',
queryDatabase: '/databases/{database_id}/query',
createDatabase: '/databases',
// Blocks
getBlock: '/blocks/{block_id}',
getBlockChildren: '/blocks/{block_id}/children',
appendBlockChildren: '/blocks/{block_id}/children',
// Search
search: '/search',
// Users
listUsers: '/users',
getUser: '/users/{user_id}'
};
// Example: Query database
const response = await fetch(`${baseUrl}/databases/${databaseId}/query`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${notionToken}`,
'Notion-Version': '2022-06-28',
'Content-Type': 'application/json'
},
body: JSON.stringify({
filter: {
property: 'Status',
select: { equals: 'In Progress' }
},
sorts: [
{ property: 'Due Date', direction: 'ascending' }
]
})
});The database query endpoint accepts filters and sorts in the request body. Unlike typical REST APIs where you might use query parameters, Notion requires POST requests with JSON bodies for complex queries. The Notion-Version header is mandatory and determines which API features are available.
Notion uses OAuth 2.0 for integration authentication. Users authorize your app to access specific pages or databases, and you receive a token scoped to only those resources.
OAuth URLs
// Notion OAuth 2.0 flow
// Step 1: Authorization URL
const authUrl = new URL('https://api.notion.com/v1/oauth/authorize');
authUrl.searchParams.set('client_id', 'YOUR_CLIENT_ID');
authUrl.searchParams.set('redirect_uri', 'https://yourapp.com/callback');
authUrl.searchParams.set('response_type', 'code');
authUrl.searchParams.set('owner', 'user'); // or 'workspace'
authUrl.searchParams.set('state', crypto.randomUUID());
// Redirect user to authUrl
// Step 2: Token exchange
const tokenResponse = await fetch('https://api.notion.com/v1/oauth/token', {
method: 'POST',
headers: {
'Authorization': `Basic ${btoa(`${clientId}:${clientSecret}`)}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
grant_type: 'authorization_code',
code: authorizationCode,
redirect_uri: 'https://yourapp.com/callback'
})
});
const { access_token, workspace_id, workspace_name } = await tokenResponse.json();
// Use access_token for API callsThe authorization URL includes an owner parameter that specifies whether the integration targets individual users or workspaces. Token exchange uses Basic authentication with your client credentials. The response includes the workspace information along with the access token.
Public pages and embeds allow sharing Notion content outside of Notion. Public page URLs use your workspace subdomain, while embed parameters control the display appearance in iframes.
Embed & Public URLs
# Public page URLs
https://{workspace}.notion.site/{Page-Title}-{id}
https://mycompany.notion.site/Docs-abc123def456
# Embed URLs (for iframes)
# Enable "Share to web" in page settings first
https://{workspace}.notion.site/{Page-Title}-{id}
# With view options
?v={view_id} # Specific database view
&lite=true # Minimal embed (no Notion branding)
# PDF export URL (requires authentication)
https://www.notion.so/api/v3/exportBlock
POST with block_id and exportOptions
# Public API for blocks
# Only works for public pages
https://api.notion.com/v1/blocks/{block_id}
# Note: Notion doesn't provide direct image URLs
# Images are proxied through Notion's CDN with signed URLsPublic pages require enabling "Share to web" in page settings. The lite parameter removes Notion branding for cleaner embeds. Be aware that image URLs in Notion content are temporary signed URLs that expire, which affects how you handle images in external applications.
When building integrations that link back to Notion, you need to construct valid URLs from page metadata. The following functions handle common URL building scenarios including slug generation and block anchors.
Building Notion Links
// Generate shareable Notion URLs
function buildNotionPageUrl(workspaceSlug, pageTitle, pageId) {
const slug = pageTitle
.replace(/[^a-zA-Z0-9\s-]/g, '')
.replace(/\s+/g, '-');
const urlId = pageId.replace(/-/g, '');
return `https://www.notion.so/${workspaceSlug}/${slug}-${urlId}`;
}
// Build database URL with filters
function buildDatabaseUrl(workspaceSlug, databaseId, viewId, filters) {
const url = new URL(`https://www.notion.so/${workspaceSlug}/${databaseId.replace(/-/g, '')}`);
if (viewId) {
url.searchParams.set('v', viewId.replace(/-/g, ''));
}
// Filters are complex - typically use view ID instead
return url.toString();
}
// Build block anchor URL
function buildBlockAnchorUrl(pageUrl, blockId) {
const url = new URL(pageUrl);
url.hash = `block-${blockId.replace(/-/g, '')}`;
return url.toString();
}
// Usage
const pageUrl = buildNotionPageUrl(
'myworkspace',
'Project Roadmap',
'abc123de-f456-7890-1234-5678901234ab'
);
// https://www.notion.so/myworkspace/Project-Roadmap-abc123def456789012345678901234abThe slug generation strips special characters and replaces spaces with hyphens. The ID is always appended without dashes at the end. When building database URLs, view IDs let you link directly to specific views like Kanban boards or calendars rather than the default table view.