Illustrative case study

A fictional business. The figures are a modelled scenario, not a client result.

← cd ../case-studiesGet Ranked On Top · SEO case study · Asia-Pacific

merlintide — case-study — zsh — 96×40

Last login: modelled session on ttys011 · Singapore

mt case-study merlintide

clientMerlintide

sectorDocument OCR API for developers · Singapore

industryTechnology & SaaS · 11 months

How an OCR API won developer searches with tutorials engineers actually bookmark

# headline

+305% API key sign-ups from organic

sparkline · M00 → M11

$ mt chart api_sign_ups_from_organic --index
M00 █████···············  100
M01 █████···············  105
M02 ██████··············  117
M03 ███████·············  133
M04 ████████············  155
M05 █████████···········  180
M06 ██████████··········  209
M07 ████████████········  241
M08 ██████████████······  277
M09 ████████████████····  317
M10 ██████████████████··  359
M11 ████████████████████  405

cat CHALLENGE.md

The challenge

Merlintide's API was faster and cheaper than rivals, but developers searching 'extract table from PDF python' only found hyperscaler docs.

The product had already won on paper: lower latency, a cheaper per-page price and cleaner JSON. But engineers don't search for “OCR vendor”. They search for the task in front of them, in the language they're writing, usually mid-sprint. Merlintide had no page that answered a single one of those tasks, and its docs were invisible to crawlers.

Meanwhile, more of those questions were being asked to AI assistants first, and the assistants quoted whoever had the clearest runnable answer. That was never Merlintide.

# query → who answered (M00)
"extract table from pdf python"
  → hyperscaler docs  #1
  → Q&A forum         #2
  → merlintide.dev   #41

# AI assistant citations: 0

mt audit docs.merlintide.dev

Diagnosis

A crawl of the docs, the logs and 312 developer queries, scored the way a search engine and an AI assistant would see them. Seven findings, three blocking.

  1. [FAIL] 01

    render: Docs were a client-rendered SPA: 0 of 214 code samples present in the initial HTML.

    fix: Static pre-render of every docs and tutorial route; code blocks shipped as real text.

  2. [FAIL] 02

    content: No pages for the 40 highest-intent task queries ("extract table from pdf python", "ocr invoice node").

    fix: Task-first tutorial library mapped one-to-one to those queries.

  3. [FAIL] 03

    schema: No TechArticle, HowTo or SoftwareSourceCode markup anywhere on the docs.

    fix: Code-sample schema on every tutorial, linked to the API reference entity.

  4. [WARN] 04

    dupes: /v1, /v2 and /latest reference pages indexed side by side with no canonical.

    fix: One canonical per endpoint; old versions noindexed and cross-linked.

  5. [WARN] 05

    answers: Tutorials opened with marketing copy; nothing an AI assistant could quote in one pass.

    fix: 40-word answer block plus a runnable snippet as the first thing on every page.

  6. [WARN] 06

    speed: Docs LCP 4.1 s on mobile (syntax highlighter blocking the main thread).

    fix: Highlighting moved to build time; LCP modelled at 1.3 s.

  7. [PASS] 07

    product: Median latency and per-page price beat the hyperscaler APIs in public benchmarks.

    fix: Benchmark page with a reproducible notebook became the link-earning asset.

3 failed, 3 warnings, 1 passed in 4.2s

cat plan.yml

The strategy

plan: Content Engine
duration: 11 # months
goal: "be the answer engineers paste, then bookmark"
tactics:
  • - name: "Developer tutorials"

    flag: --tutorials=48

    Forty-eight task-shaped tutorials (one query, one outcome) in Python, Node, Go and cURL, each ending in a free-key snippet that runs on the first paste.

  • - name: "Code-sample schema"

    flag: --schema=SoftwareSourceCode

    TechArticle + SoftwareSourceCode markup with language, runtime and dependency fields, so search engines can read a sample as code rather than prose.

  • - name: "AI Overviews"

    flag: --answers=first

    Every page leads with a quotable answer, a minimal code block and a version-stamped date: the format AI assistants cite when engineers ask them how.

  • - name: "Docs SEO"

    flag: --docs=static

    Pre-rendered docs, one canonical per endpoint, a crawlable sidebar and internal links from each tutorial into the exact reference page it uses.

# the Content Engine plan sets the cadence; the tactics above are how it was pointed at developer intent.

git log --reverse --oneline

11 months, commit by commit

  1. a41c9e2M01

    audit: crawl docs, map 312 developer queries

    Search console, log files and competitor docs crawled; intent grouped by task.

    105
  2. 7be03d1M02

    feat(docs): static pre-render + canonicals

    Code samples visible to crawlers for the first time.

    117
  3. c90f4aaM03

    feat(tutorials): first 8 python tasks

    Tables, invoices, receipts, handwriting; each with a runnable snippet.

    133
  4. 13d7e6bM04

    feat(schema): SoftwareSourceCode on samples

    Validated against the rich result tests; zero errors.

    155
  5. e2a58f0M05

    feat(tutorials): node + go ports

    Same tasks, three more runtimes, hreflang-style language switcher.

    180
  6. 5f61b3cM06

    perf: build-time highlighting, LCP 1.3s

    Main-thread work on docs pages cut by roughly two thirds.

    209
  7. 98c2d47M07

    feat(answers): answer-first rewrite

    First AI assistant citations of tutorial pages logged.

    241
  8. 0ad4e19M08

    feat(bench): reproducible benchmark notebook

    Picked up by two newsletters and a framework's docs.

    277
  9. b7e3f82M09

    feat(tutorials): 48 tasks live

    Long-tail coverage complete; internal links into reference.

    317
  10. 4c18ad5M10

    chore: refresh samples for SDK v3

    Version stamps updated so answers stay quotable.

    359
  11. f03e6c9M11

    release: sign-up flow inside tutorials

    Free key issued inline; organic sign-ups at their modelled peak.

    405

# right column: organic API sign-ups, index M00 = 100

curl -s mt.dev/cs | jq .metrics

Results

{
  "api_sign_ups_from_organic": "+305%",
  "tutorial_sessions": "+460%",
  "ai_assistant_citations": "86",
  "top_3_developer_queries": "+148",
  "months": 11,
  "modelled": true
}

Modelled scenario for a fictional business — not a client result. Rankings and traffic are never guaranteed; see our Terms.

  • $ mt chart api_sign_ups_from_organic

    +305%

    API sign-ups from organic

    M00 100M11 405

  • $ mt chart tutorial_sessions

    +460%

    Tutorial sessions

    M00 100M11 560

  • $ mt chart ai_assistant_citations

    86

    AI assistant citations

    M00 0M11 86

  • $ mt chart top_3_developer_queries

    +148

    Top-3 developer queries

    M00 0M11 148

mt rank --top 10

Rankings & the SERP, before and after

# 10 of 10 queries · press / to focus

Modelled Google positions before and after, by query
queryintentvol/moM00M11
"extract table from pdf python"task6,600#41#2
"ocr api"commercial4,400#27#3
"invoice ocr node js"task1,300—#1
"receipt ocr api free tier"commercial880—#2
"pdf to json python"task3,600#63#3
"handwriting recognition api"commercial2,400#38#4
"parse scanned pdf golang"task480—#1
"tesseract vs cloud ocr"compare1,900#52#2
"ocr bounding boxes json"task590—#2
"extract text from image curl"task1,000#74#5
$ mt serp "extract table from pdf python" --m00
  1. #1cloud-hyperscaler.example/docsDocument AI quickstart
  2. #2qa-forum.exampleHow to read a PDF table? [closed]
  3. #3other-cloud.example/docsTextract developer guide
  4. -#41merlintide.devMerlintide | Fast OCR API
$ mt serp "extract table from pdf python" --m11
  1. +AIAI overviewcites merlintide.dev/tutorials/pdf-tables
  2. #1cloud-hyperscaler.example/docsDocument AI quickstart
  3. +#2merlintide.dev/tutorialsExtract tables from a PDF in Python (9 lines)
  4. #3qa-forum.exampleHow to read a PDF table? [closed]

mt plan --like merlintide

Get a plan like this

Built on Content Engine: tutorials and docs shaped around the tasks your buyers actually type, marked up so search engines and AI assistants can read the code.

$ cd ../case-studies # all case studies