Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions packages/notion-client/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,44 @@ const collectionData = await api.getCollectionData(
)
```

### Using Custom API Base URL

**Important:** Due to recent changes in Notion's internal API you may need to specify your Notion site's subdomain when accessing public pages with collections/databases to avoid HTTP 530 errors.

```ts
import { NotionAPI } from 'notion-client'

// For public Notion pages, use your site's subdomain
const api = new NotionAPI({
apiBaseUrl: 'https://your-subdomain.notion.site/api/v3'
})

const page = await api.getPage('your-page-id')
```

**How to find your subdomain:**

1. Open your Notion page in a web browser
2. Look at the URL: `https://your-subdomain.notion.site/Page-Title-xxxxx`
3. Copy the `your-subdomain` part
4. Use it in the `apiBaseUrl` parameter

**Example:**

If your Notion page URL is `https://acme-corp.notion.site/Team-Wiki-abc123`, then:

```ts
const api = new NotionAPI({
apiBaseUrl: 'https://acme-corp.notion.site/api/v3'
})
```

**Troubleshooting:**

- ❌ `Error 530` when querying collections → Update `apiBaseUrl` with your subdomain
- ❌ Using the old endpoint `https://www.notion.so/api/v3` → Switch to your site's URL
- ✅ Private pages with `authToken` → The default endpoint usually works fine

### Fetch a database's content

You can pass a database ID to the `getPage` method. The response is an object which contains several important properties:
Expand Down
74 changes: 73 additions & 1 deletion packages/notion-client/src/notion-api.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { expect, test } from 'vitest'
import { expect, test, vi } from 'vitest'

import { NotionAPI } from './notion-api'

Expand Down Expand Up @@ -47,3 +47,75 @@ for (const pageId of pageIdFixturesFailure) {
await expect(() => api.getPage(pageId)).rejects.toThrow()
})
}

test('NotionAPI.getPage should log a helpful error on 530 errors', async () => {
const consoleErrorSpy = vi
.spyOn(console, 'error')
.mockImplementation(() => {})

const pageId = 'bdecdf15-0d0e-40cb-9f34-12be132335d4' // Use a valid UUID format
const collectionId = 'collection-id'
const viewId = 'view-id'

const api = new NotionAPI()

// Spy on the private fetch method to isolate the mock to this test
const fetchSpy = vi
.spyOn(api as any, 'fetch')
.mockImplementation(async (params: any) => {
const { endpoint } = params
if (endpoint === 'loadPageChunk') {
return {
recordMap: {
block: {
[pageId]: {
value: {
id: pageId,
type: 'collection_view_page',
collection_id: collectionId,
view_ids: [viewId]
}
}
},
collection: {
[collectionId]: {
value: { id: collectionId, name: [['Test Collection']] }
}
},
collection_view: {
[viewId]: {
value: { id: viewId, type: 'table' }
}
}
}
}
}

if (endpoint === 'queryCollection') {
const error: any = new Error('Response code 530')
error.status = 530
error.response = { status: 530 }
throw error
}

return {}
})

const page = await api.getPage(pageId, {
fetchCollections: true,
throwOnCollectionErrors: false
})

expect(page).toBeTruthy()
expect(consoleErrorSpy).toHaveBeenCalledWith(
expect.stringContaining('Notion API Error 530: Collection query failed')
)
expect(consoleErrorSpy).toHaveBeenCalledWith(
expect.stringContaining(
"Solution: Configure NotionAPI with your site's subdomain"
)
)

fetchSpy.mockRestore()
consoleErrorSpy.mockRestore()
})
23 changes: 23 additions & 0 deletions packages/notion-client/src/notion-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,29 @@ export class NotionAPI {
// It's possible for public pages to link to private collections,
// in which case Notion returns a 400 error. This may be that or it
// may be something else.

// Special handling for 530 errors (API endpoint issues)
const is530Error =
err.response?.status === 530 ||
err.status === 530 ||
err.message?.includes('530')

if (is530Error) {
console.error(
'\n Notion API Error 530: Collection query failed\n' +
'━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n' +
' This usually means the API endpoint needs to be updated.\n\n' +
" Solution: Configure NotionAPI with your site's subdomain:\n\n" +
' const api = new NotionAPI({\n' +
" apiBaseUrl: 'https://YOUR-SUBDOMAIN.notion.site/api/v3'\n" +
' })\n\n' +
' Find your subdomain in your Notion page URL:\n' +
' https://YOUR-SUBDOMAIN.notion.site/...\n\n' +
' Learn more: https://github.com/NotionX/react-notion-x/tree/master/packages/notion-client#using-custom-api-base-url\n' +
'━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'
)
}

console.warn(
'NotionAPI collectionQuery error',
{ pageId, collectionId, collectionViewId },
Expand Down