Skip to main content

Overview

The doc() URL builder generates immutable, CDN-cacheable URLs for every document property. URLs are constructed at build time with zero API calls — use them directly in <img>, <a>, or any HTML attribute. Think Cloudinary for images, but for documents.

Quick start

import { doc } from '@okrapdf/runtime';

const d = doc('ocr-7fK3x');

d.url()                          // full document
d.thumbnail.url()                // cover thumbnail
d.pages[0].image.url()           // page as PNG
d.pages[0].markdown.url()        // page as markdown
d.entities.tables.url()          // all tables
d.entities.tables[0].url()       // first table (JSON)
d.entities.tables[0].url({ format: 'csv' })   // first table (CSV)
d.entities.tables[0].url({ format: 'html' })  // first table (HTML)
d.entities.figures.url()         // all figures
d.url({ format: 'json', include: ['tables', 'text'] })  // filtered export
doc() accepts canonical IDs (ocr-*) and short public aliases (d_*) when available.

All generated URLs

For a document ocr-7fK3x, the builder generates:
PropertyURL
Documenthttps://api.okrapdf.com/v1/documents/ocr-7fK3x
Thumbnailhttps://api.okrapdf.com/v1/documents/ocr-7fK3x/thumbnail
Page 0https://api.okrapdf.com/v1/documents/ocr-7fK3x/pages/0
Page 0 Imagehttps://api.okrapdf.com/v1/documents/ocr-7fK3x/pages/0/image
Page 0 Markdownhttps://api.okrapdf.com/v1/documents/ocr-7fK3x/pages/0/markdown
All Tableshttps://api.okrapdf.com/v1/documents/ocr-7fK3x/entities/tables
Table 0 (JSON)https://api.okrapdf.com/v1/documents/ocr-7fK3x/entities/tables/0
Table 0 (CSV)https://api.okrapdf.com/v1/documents/ocr-7fK3x/entities/tables/0?format=csv
All Figureshttps://api.okrapdf.com/v1/documents/ocr-7fK3x/entities/figures

Use in React / JSX

import { doc } from '@okrapdf/runtime';

function DocumentCard({ docId }: { docId: string }) {
  const d = doc(docId);
  return (
    <article>
      <img src={d.thumbnail.url()} alt="Document cover" />
      <h2>Report</h2>
      <ul>
        <li><a href={d.pages[0].image.url()}>View page 1</a></li>
        <li><a href={d.entities.tables[0].url({ format: 'csv' })}>Download table (CSV)</a></li>
        <li><a href={d.url({ format: 'json' })}>Full JSON export</a></li>
      </ul>
    </article>
  );
}

Use as og:image

import { doc } from '@okrapdf/runtime';

export function generateMetadata({ params }) {
  const d = doc(params.docId);
  return {
    openGraph: {
      images: [d.thumbnail.url()],
    },
  };
}

PDF lead magnet landing page

Upload a whitepaper, get a landing page with zero backend work:
const session = await okra.sessions.create('whitepaper.pdf', { wait: true });
await session.publish();

const d = doc(session.id);

// Everything you need for a lead magnet page:
const ogImage = d.thumbnail.url();              // social preview
const heroPreview = d.pages[0].image.url();     // hero section
const tableDownload = d.entities.tables[0].url({ format: 'csv' }); // CTA

Provider transformations

Like Cloudinary’s /w_300/image.jpg, OkraPDF uses /t_{provider}/ to select the extraction backend. Same document, different output:
import { doc } from '@okrapdf/runtime';

// Default extraction
const d = doc('ocr-7fK3x');
d.pages[1].markdown.url()
// → /v1/documents/ocr-7fK3x/pages/1/markdown

// LlamaParse extraction
const llama = doc('ocr-7fK3x', { provider: 'llamaparse' });
llama.pages[1].markdown.url()
// → /v1/documents/ocr-7fK3x/t_llamaparse/pages/1/markdown

// Compare side-by-side
doc('ocr-7fK3x', { provider: 'googleocr' }).pages[1].url()
doc('ocr-7fK3x', { provider: 'docling' }).pages[1].url()
doc('ocr-7fK3x', { provider: 'unstructured' }).pages[1].url()
The provider segment is router-only — stripped before forwarding to the document. It tells the system which extraction backend to read from.

Artifact slugs

When fileName is provided, URLs get cache-friendly, human-readable suffixes:
const d = doc('ocr-7fK3x', { fileName: 'quarterly-report.pdf' });

d.url()
// → /v1/documents/ocr-7fK3x/quarterly-report_a3f8b2.json

d.thumbnail.url()
// → /v1/documents/ocr-7fK3x/thumbnail/quarterly-report_a3f8b2.png

d.pages[1].image.url()
// → /v1/documents/ocr-7fK3x/pages/1/image/quarterly-report_a3f8b2.png

d.entities.tables[0].url({ format: 'csv' })
// → /v1/documents/ocr-7fK3x/entities/tables/0/quarterly-report_a3f8b2.csv?format=csv
The suffix is a 6-character FNV-1a hash of the document ID. You can also provide a custom suffix:
const d = doc('ocr-7fK3x', { fileName: 'report.pdf', suffix: 'xyz789' });
Artifact slugs are cosmetic — the router strips them before forwarding. They make URLs mime-explicit and shareable.

Browser usage

Use the URL builder in browser code without Node.js:
<script type="module">
  import { doc } from 'https://cdn.jsdelivr.net/npm/@okrapdf/runtime/dist/browser.js';

  const d = doc('ocr-7fK3x');
  document.querySelector('#cover').src = d.thumbnail.url();
  document.querySelector('#csv-link').href = d.entities.tables[0].url({ format: 'csv' });
</script>
Or use the global export:
<script src="https://cdn.jsdelivr.net/npm/@okrapdf/runtime/dist/browser.js"></script>
<script>
  const d = window.OkraRuntime.doc('ocr-7fK3x');
  console.log(d.pages[1].markdown.url());
</script>
The browser bundle exports only doc() — no Node.js dependencies. For data fetching in the browser, use the generated URLs with fetch() directly.

Custom base URL

For self-hosted deployments:
const d = doc('ocr-7fK3x', 'https://docs.mycompany.com');
d.thumbnail.url(); // https://docs.mycompany.com/v1/documents/ocr-7fK3x/thumbnail

Private vs public URLs

URLs always resolve to the same path. Access depends on whether the document is published:
  • Private (default): URLs return 404 without API key
  • Published: URLs are publicly accessible, CDN-cacheable
// Make URLs public
const session = okra.sessions.from(docId);
await session.publish();
// Now all doc(docId).*.url() paths return content without auth

App reader URL (unchanged)

If you’re linking to Okra’s hosted reader UI, keep using: https://app.okrapdf.com/ocr/{canonicalId}/reader