Skip to main content
The Notion SDK provides methods to work with page content as Markdown, making it easy to export or programmatically update page content.

pages.retrieveMarkdown

Retrieves a page’s content rendered as Notion-flavored Markdown.

Method Signature

notion.pages.retrieveMarkdown(args: GetPageMarkdownParameters): Promise<PageMarkdownResponse>

Parameters

page_id
string
required
The ID of the page (or block) to retrieve as markdown. Non-navigable block IDs from truncated responses can be passed here to fetch their subtrees.
include_transcript
boolean
Whether to include meeting note transcripts. Defaults to false.
  • When true: Full transcripts are included in the markdown
  • When false: A placeholder with the meeting note URL is shown instead
auth
string
Bearer token for authentication. Overrides the client-level authentication.

Response

object
string
Always "page_markdown"
id
string
The ID of the page or block
markdown
string
The page content rendered as enhanced Markdown
truncated
boolean
Whether the content was truncated due to exceeding the record count limit
unknown_block_ids
array
Block IDs that could not be loaded (appeared as <unknown> tags in the markdown). Pass these IDs back to this endpoint to fetch their content separately.

Examples

Basic Markdown Retrieval

const response = await notion.pages.retrieveMarkdown({
  page_id: "897e5a76-ae52-4b48-9fdf-e71f5945d1af",
})

console.log(response.markdown)

Save Page as Markdown File

import * as fs from "fs"

const response = await notion.pages.retrieveMarkdown({
  page_id: "897e5a76-ae52-4b48-9fdf-e71f5945d1af",
})

fs.writeFileSync("page-export.md", response.markdown, "utf8")
console.log("Page exported to page-export.md")

Include Meeting Transcripts

const response = await notion.pages.retrieveMarkdown({
  page_id: "897e5a76-ae52-4b48-9fdf-e71f5945d1af",
  include_transcript: true,
})

console.log("Markdown with transcripts:", response.markdown)

Handle Truncated Content

const response = await notion.pages.retrieveMarkdown({
  page_id: "897e5a76-ae52-4b48-9fdf-e71f5945d1af",
})

if (response.truncated) {
  console.log("Content was truncated")
  console.log("Unknown block IDs:", response.unknown_block_ids)
  
  // Fetch unknown blocks separately
  for (const blockId of response.unknown_block_ids) {
    const blockMarkdown = await notion.pages.retrieveMarkdown({
      page_id: blockId,
    })
    console.log(`Block ${blockId}:`, blockMarkdown.markdown)
  }
}

pages.updateMarkdown

Updates a page’s content using Notion-flavored Markdown. You can insert new content or replace existing content ranges.

Method Signature

notion.pages.updateMarkdown(args: UpdatePageMarkdownParameters): Promise<PageMarkdownResponse>

Parameters

page_id
string
required
The ID of the page to update.
type
string
required
The type of update operation. One of:
  • "insert_content" - Insert new content into the page
  • "replace_content_range" - Replace a range of existing content

For insert_content type:

insert_content
object
required
Configuration for inserting new content.

For replace_content_range type:

replace_content_range
object
required
Configuration for replacing existing content.
auth
string
Bearer token for authentication. Overrides the client-level authentication.

Response

Same as retrieveMarkdown - returns a PageMarkdownResponse with the updated content.

Examples

Insert Content at End

const response = await notion.pages.updateMarkdown({
  page_id: "897e5a76-ae52-4b48-9fdf-e71f5945d1af",
  type: "insert_content",
  insert_content: {
    content: `
## New Section

This content is added to the end of the page.

- Item 1
- Item 2
- Item 3
`,
  },
})

console.log("Content inserted")

Insert Content After Specific Text

const response = await notion.pages.updateMarkdown({
  page_id: "897e5a76-ae52-4b48-9fdf-e71f5945d1af",
  type: "insert_content",
  insert_content: {
    content: `
### Additional Details

More information about the topic.
`,
    after: "## Introduction...## Methods",
  },
})

console.log("Content inserted after Introduction section")

Replace Content Range

const response = await notion.pages.updateMarkdown({
  page_id: "897e5a76-ae52-4b48-9fdf-e71f5945d1af",
  type: "replace_content_range",
  replace_content_range: {
    content: `
## Updated Section

This is the new content.
`,
    content_range: "## Old Section...## Next Section",
  },
})

console.log("Content replaced")

Replace with Permission to Delete

const response = await notion.pages.updateMarkdown({
  page_id: "897e5a76-ae52-4b48-9fdf-e71f5945d1af",
  type: "replace_content_range",
  replace_content_range: {
    content: "## Simplified Section\n\nNew simplified content.",
    content_range: "## Complex Section...## Conclusion",
    allow_deleting_content: true,
  },
})

console.log("Content replaced (including child pages)")

Update Documentation from Git

import * as fs from "fs"

// Read markdown from a file
const markdownContent = fs.readFileSync("./docs/api-guide.md", "utf8")

// Replace the documentation section
const response = await notion.pages.updateMarkdown({
  page_id: "897e5a76-ae52-4b48-9fdf-e71f5945d1af",
  type: "replace_content_range",
  replace_content_range: {
    content: markdownContent,
    content_range: "## API Guide...## Examples",
  },
})

console.log("Documentation updated from Git")

Append Daily Log Entry

const today = new Date().toISOString().split("T")[0]

const response = await notion.pages.updateMarkdown({
  page_id: "daily-log-page-id",
  type: "insert_content",
  insert_content: {
    content: `
### ${today}

- Completed feature X
- Fixed bug in module Y
- Updated documentation
`,
  },
})

console.log("Daily log entry added")

Content Selection Format

The after and content_range parameters use an ellipsis format to select content:
"start text...end text"
  • Start text: The beginning of the content range
  • End text: The end of the content range
  • Ellipsis (...): Separator between start and end

Examples:

  • "## Introduction...## Methods" - Selects from “Introduction” heading to “Methods” heading
  • "First paragraph...Last paragraph" - Selects text between these paragraphs
  • "# Title...---" - Selects from title to a divider

Notion-Flavored Markdown

Notion’s markdown flavor supports:
  • Standard Markdown syntax (headings, lists, bold, italic, etc.)
  • Code blocks with syntax highlighting
  • Tables
  • Callouts and quotes
  • Links and inline mentions
  • LaTeX equations
  • Embeds and media
For detailed syntax, see Notion’s Markdown documentation.

Important Notes

When using replace_content_range, be careful with the content_range selection. If the selection is ambiguous or matches multiple locations, the operation may fail or produce unexpected results.
The truncated field in the response indicates if the page has more content than can be returned in a single response. Use the unknown_block_ids to fetch additional content.
Use markdown operations for:
  • Exporting Notion pages to static site generators
  • Programmatically updating documentation
  • Syncing content from external sources
  • Automating content generation

See Also

Build docs developers (and LLMs) love