0

Duplicate Page

by
Published today

Copy a page's title, icon, cover and content into a new page under a parent page.

Script notion Verified

The script

Submitted by hugo989 Typescript (fetch-only)
Verified 3 hours ago
1
//native
2

3
/**
4
 * Duplicate Page
5
 * Copy a page's title, icon, cover and content into a new page under a parent page, via Notion-flavored Markdown. Database properties, comments and child pages' own content are not copied; uploaded-file icons and covers are skipped.
6
 */
7
export async function main(
8
  auth: RT.Notion,
9
  page_id: string,
10
  parent_page_id: string,
11
  title: string | undefined
12
) {
13
  const headers = {
14
    Authorization: `Bearer ${auth.token}`,
15
    Accept: "application/json",
16
    "Notion-Version": "2026-03-11",
17
  }
18
  const get = async (path: string) => {
19
    const response = await fetch(`https://api.notion.com/v1/${path}`, {
20
      headers,
21
    })
22
    if (!response.ok) {
23
      throw new Error(`${response.status} ${await response.text()}`)
24
    }
25
    return await response.json()
26
  }
27

28
  const page = await get(`pages/${page_id}`)
29
  const content = await get(`pages/${page_id}/markdown`)
30
  if (content.truncated) {
31
    throw new Error(
32
      "Page is too large to copy in one request (truncated markdown)"
33
    )
34
  }
35
  const source = Object.values(page.properties).find(
36
    (p: any) => p.type === "title"
37
  ) as { title: { plain_text: string }[] }
38
  const keep = (v: any) =>
39
    v && v.type !== "file" && v.type !== "file_upload" ? v : undefined
40

41
  const body: { [key: string]: any } = {
42
    parent: { type: "page_id", page_id: parent_page_id },
43
    properties: {
44
      title: {
45
        title: [
46
          {
47
            text: {
48
              content: title || source.title.map((t) => t.plain_text).join(""),
49
            },
50
          },
51
        ],
52
      },
53
    },
54
    icon: keep(page.icon),
55
    cover: keep(page.cover),
56
  }
57
  if (content.markdown) body.markdown = content.markdown
58

59
  const response = await fetch("https://api.notion.com/v1/pages", {
60
    method: "POST",
61
    headers: { ...headers, "Content-Type": "application/json" },
62
    body: JSON.stringify(body),
63
  })
64

65
  if (!response.ok) {
66
    throw new Error(`${response.status} ${await response.text()}`)
67
  }
68

69
  return await response.json()
70
}
71