DocRaptor — компетентный продукт. Оборачивает Prince — золотой стандарт движков HTML-в-PDF — в хостинговый REST API с retry, асинхронными job-ами и приличной документацией. Существует более десяти лет, и для многих команд это очевидный выбор «не хочу самостоятельно эксплуатировать Prince».
Мы — инструмент другой формы. gPdf вообще не принимает HTML; берёт структурированный JSON и рендерит напрямую на edge Cloudflare. Разница прайс-листа при 100K страниц/месяц: $5/месяц (gPdf Basic) vs $89/месяц (DocRaptor Basic) — около 18×. Эта разница не открывающая промо. Она структурная. Этот пост объясняет, почему структура производит эту цену, и где каждый инструмент действительно подходит.
Две архитектуры рядом
| Слой | DocRaptor (HTML → PDF) | gPdf (JSON → PDF) |
|---|---|---|
| Вход | HTML + CSS (с расширениями Prince paged-media) | JSON DocumentRequest |
| Renderer | Prince (компилированный C++ движок) | Собственный движок Rust, скомпилированный в WebAssembly |
| Хостинг | Централизованные серверы DocRaptor (датацентр US) | Cloudflare Workers, каждый CF colo (300+ городов) |
| Холодный старт | Серверный пул воркеров | Загрузка V8 isolate, однозначные мс |
| Compute на рендер | Pass layout по HTML/CSS, затем Prince пагинирует | Прямая вёрстка, без pass интерпретации layout |
| p50 на рендер | ~250–800 мс wall-clock (сеть + рендер) | ~3–8 мс (сеть + рендер) |
| Детерминизм вывода | Высокий (Prince зрелый) | Байт-идентичный (тот же JSON → те же байты) |
Если вы читаете эти две колонки как «универсальный HTML-принтер» vs «целенаправленно построенный рендерер документов», вы уже поняли архитектурное решение. Всё остальное (латентность, стоимость, даже списки функций) — ниже по течению этого единственного выбора.
Налог Prince
Prince хорош. Также делает работу, в которой большинство workflow счёт/чек/этикетка не нуждаются: реализовать CSS Paged Media — правила переноса страниц, бегущие headers, сноски, перекрёстные ссылки, генерируемый контент — для произвольного HTML, который пользователь может бросить.
Эта универсальность имеет runtime-стоимость. Чтобы пагинировать произвольный HTML, движок должен:
- Распарсить и валидировать HTML
- Разрешить CSS-каскад (потенциально с собственными расширениями Prince)
- Построить дерево рендера
- Запустить multi-pass layout (особенно для таблиц через страницы или балансирующих столбцов)
- Разрешить перекрёстные ссылки между страницами
- Эмитировать PDF-объекты
Большинство этих pass-ей — стоимость принятия HTML как входа. Если ваш вход уже структурированные данные (а почти всегда так — ваш счёт существует как JSON-объект до того, как вы оборачиваете его в HTML), вы платите за эти pass-ы compute и латентностью на каждом рендере, и они не добавляют ценности выводу.
gPdf полностью пропускает шаг интерпретации layout. JSON DocumentRequest уже структурно специфицирует layout страницы — { pages: [{ size, elements: [...] }] }. Renderer верстает элементы, пагинирует таблицы/списки детерминистично и эмитирует PDF. Никакого CSS-каскада для разрешения, никакого float-layout для вычисления, никакого pass разрешения перекрёстных ссылок.
Результат: тот же одностраничный счёт, занимающий ~300 мс на DocRaptor, занимает ~3 мс на gPdf. Мы быстрее не потому, что написали более быстрый Prince — мы быстрее потому, что не делаем большинства того, что делает Prince.
«Слишком дёшево, чтобы быть правдой» — это реальное возражение в закупках
Адресуем это напрямую, потому что всплывает в каждом B2B-звонке продаж.
«$5/месяц за 100K рендеров. DocRaptor — $89. Anvil — $0,10/PDF (то есть $10.000 при том же объёме). Что с вами не так?»
Три честные причины, по которым мы можем взимать это:
1. Мы не запускаем браузер
DocRaptor амортизирует Prince-инфраструктуру между клиентами. gPdf амортизирует один Cloudflare Worker, что стоит около $0,50/миллион запросов на Workers Bundled. С JSON-формой входа наш renderer берёт около 1,5 мс CPU на рендер. Накиньте 50% маржи и вы всё ещё в диапазоне центов-за-тысячу-рендеров. Арифметика — это цена.
2. Мы не запускаем control plane
Никаких асинхронных job-ов, callback-ов, очереди retry, хранилища документов, UI ссылок предпросмотра, multi-tenant БД. Каждый рендер — единственный round-trip к stateless-функции и обратно. Это удаляет всю поверхность ops, которую большинство компаний «PDF API» бюджетируют — что также является поверхностью, оправдывающей их цену.
3. Модель самоотбирается из workload-ов, на которых мы потеряли бы деньги
Если ваш документ действительно нуждается в HTML-в-PDF (60-страничный юридический договор, сложный CSS-Grid отчёт), вы отскочите от JSON-модели в первый час и пойдёте в DocRaptor всё равно. Нам не нужно защитно ценить эти workload-ы, потому что они саморутятся. Нужно только ценить длинный, но узкий хвост workload-ов «структурированные-данные-в-документ», где стоимость на рендер действительно крошечная.
Вместе: $5/100K — не loss-leader, это реальная себестоимость плюс маржа. Можем держать её там бесконечно, потому что базовый compute действительно настолько дёшев, когда вы не отгружаете браузер.
Где DocRaptor — правильный выбор
Стараемся не писать корыстные сравнения. Случаи, где DocRaptor реально побеждает:
- Ваш вход — HTML, который вы не контролируете полностью. Отчёты, генерируемые пользователями, шаблоны третьих сторон, Markdown-из-CMS-рендерится-в-HTML. Не хотите писать JSON-mapper для произвольных входов.
- Нужны функции CSS Paged Media, поддерживаемые Prince. Бегущие headers/footers по главам, сложный reflow сносок, именованные селекторы страниц, генерируемые оглавления, индексы. gPdf имеет структурированные эквиваленты для общего подмножества, но если вы живёте в селекторах
@page :left, Prince — ваш друг. - У вас контент-команда, пишущая HTML/CSS, а не JSON. Не навязывайте JSON-workflow авторинга не-инженерной команде. Они вас возненавидят.
- Async + callbacks + хранилище документов как сервис. DocRaptor хранит сгенерированные PDF и даёт вам подписанные URL для доставки. gPdf строго stateless — ваш код хранит результат.
Если вы в любом из этих вёдер, оставайтесь на DocRaptor. Это правильный инструмент.
Где gPdf — правильный выбор
Зеркальное отражение:
- Ваши входы уже структурированные данные (строки БД, JSON API payload-ы, сообщения очереди).
- Латентность важна — интерактивные checkout-flow, печать этикеток в реальном времени, генерация выписок по запросу.
- Вам важна байт-идентичная воспроизводимость для тестов / audit trail / хранения электронных счетов.
- Вы чувствительны к стоимости при любом объёме выше нескольких тысяч рендеров/месяц.
- Нужны штрих-коды (GS1-128, QR, Data Matrix, PDF417, Aztec, MaxiCode) с суб-миллиметровой точностью.
- Нужен PDF/A (1b/2b/3b/4) или вложения Factur-X / ZUGFeRD для compliance — особенно актуально для российского ЭДО (электронного документооборота) с УПД в формате XML и для интеграции с европейскими партнёрами по EN 16931.
- Вы предпочитаете не запускать pipeline JSON-в-HTML-в-PDF, когда можете запустить pipeline JSON-в-PDF.
Конкретное замечание для российских команд
В контексте российского ЭДО (электронного документооборота) — обязательного для счетов-фактур (УПД) с 2014, для маркированных товаров с 2019, и расширяющегося на B2B с 2024 — gPdf производит как печатную форму, так и может прикрепить XML-структуру через PDF/A-3:
curl -X POST https://gpdf.com/api/v1/e-invoice/render \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
--data '{
"document": { "pages": [{ "size": "a4", "elements": [...] }] },
"einvoice": {
"format": "factur-x",
"profile": "BASIC",
"xml": "<rsm:CrossIndustryInvoice>...</rsm:CrossIndustryInvoice>"
}
}' \
--output schet-faktura.pdf
Без post-pass Ghostscript, без второго инструмента для прикрепления XML, без лотереи валидации между шагами. Байты вывода байт-идентичны между версиями движка, поэтому ваш hash хранения для 5-летнего фискального обязательства может оставаться стабильным.
Миграция механическая, не стратегическая
Распространённая забота: «Переход означает переписать все наши шаблоны». Обычно нет. Большинство шаблонов HTML-в-PDF — 20% layout (что один раз становится JSON-структурой) и 80% интерполяция данных (что точно одинаково независимо от того, что принимает renderer).
Практический путь:
- Выберите один тип документа для миграции. Начните с самого высокого объёма — самая большая экономия, самый малый радиус взрыва.
- Возьмите интерфейс данных HTML-шаблона (переменные, которые он интерполирует) и напишите небольшую функцию
mapToDocumentRequest(data). - Итерируйте против Playground, пока вывод не совпадёт.
- A/B в продакшене: маршрутизируйте 5% трафика на gPdf две недели. Diff PDF. Сравните счета.
- Двигайтесь вперёд или назад на основе данных, а не вибраций.
TL;DR
| DocRaptor | gPdf | |
|---|---|---|
| Лучше для | HTML → PDF для произвольного контента | JSON → PDF для структурированных документов |
| Цена (100K страниц/месяц) | $89 | $5 |
| Рендер p50 | 250–800 мс | 3–8 мс |
| Edge-deployed | ❌ централизованный | ✅ 300+ Cloudflare colos |
| Async + storage | ✅ включено | ❌ stateless по дизайну |
| PDF/A + Factur-X / ZUGFeRD | ⚠️ через расширения Prince | ✅ встроено |
Если ваши документы — структурированные данные, замаскированные под HTML для renderer-а, вы платите за шаг трансляции, который не должен существовать. Попробуйте Playground — опишите один из ваших счетов в JSON, отрендерите в браузере менее чем за 5 мс, посмотрите, совпадает ли разрыв с вашей интуицией.