Wanna export your articles to local markdown files but found the built-in export function hard to use? Use Ruby with the notoin-sdk-ruby gem and scripts below to achieve that easily.

Assuming you are familiar with Ruby, here is a brief guide:

Step 1: get a token and authorize it

For simplicity, create a new integration here and get it’s internal integration token.

Authorize the integration by inviting it to the target page or database.

Reference: Notion’s getting started for developers

Step 2: install the Notion SDK for Ruby

gem install notion-sdk-ruby

Step 3: patch the gem with to_md method

It’s just a monkey-patch. Feel free to modify according to your need:

require 'notion-sdk-ruby'

class Notion::Block
  def to_md
    prefix = ''
    suffix = ''

    case type
    when 'paragraph'
      # do nothing
    when /heading_(\d)/
      prefix = '#' * Regexp.last_match(1).to_i + ' '
      self[type]['rich_text'].map { _1['annotations']['bold'] = false } # unbold headings
    when 'callout'
      # do nothing
    when 'quote'
      prefix = '> '
    when 'bulleted_list_item'
      prefix = '- '
    when 'numbered_list_item'
      prefix = '1. '
    when 'to_do'
      prefix = to_do['checked'] ? '- [x] ' : '- [ ] '
    when 'toggle'
      # do nothing
    when 'code'
      prefix = "```#{code['language'].split.first}\n"
      suffix = "\n```"
    when 'image'
      return "![#{RichText.to_md(image['caption'])}](#{image[image['type']]['url']})"
    when 'equation'
      return "$$#{equation['expression']}$$"
    when 'divider'
      return '---'
    else
      raise 'Unable to convert the block'
    end

    # Only for types with rich_text, others should return in `case`
    prefix + RichText.to_md(self[type]['rich_text']) + suffix
  rescue RuntimeError => e
    puts "#{e.message}: #{JSON.pretty_generate(to_h)}"
    "```json\n#{JSON.pretty_generate(to_h)}\n```"
  end
end

class Notion::RichText
  ATTRIBUTES = %w[
    plain_text href annotations type text mention equation
  ].each { attr_reader _1 }

  def self.to_md(obj)
    obj.is_a?(Array) ? obj.map { |item| new(item).to_md }.join : new(obj).to_md
  end

  def initialize(data)
    ATTRIBUTES.each { instance_variable_set("@#{_1}", data[_1]) }
  end

  def to_md
    md = plain_text

    # Shortcut for equation
    return "$#{md}$" if type == 'equation'

    md = "<u>#{md}</u>" if annotations['underline']
    md =   "`#{md}`"    if annotations['code']
    md =  "**#{md}**"   if annotations['bold']
    md =   "*#{md}*"    if annotations['italic']
    md =  "~~#{md}~~"   if annotations['strikethrough']
    md =   "[#{md}](#{href}){:target=\"_blank\"}" if href

    md
  end
end

Check the latest version of this script on GitHub Gist

Step 4: begin with this starter

That’s all you need. Begin with your own script with following starter:

# Create a client for Notion APIs
client = Notion::Client.new(token: 'PUT_YOUR_TOKEN_HERE'))

# A simplest example
pages = client.databases.query_all('YOUR_DATABASE_ID')
blocks = client.blocks.children.list(page.first.id)
puts blocks.map(&:to_md).join("\n\n")

Check the latest version of this script on GitHub Gist


That’s all you need to convert Notion pages to markdown with Ruby.