Website zu PDF API#

Der Endpunkt POST /v1/convert/website-to-pdf crawlt eine ganze Website (per Sitemap-Parsing oder einem vollständigen Breadth-First-Crawl), konvertiert jede gefundene Seite in ein hochwertiges PDF und bündelt die Ergebnisse in einem einzigen ZIP-Archiv. Jobs laufen immer asynchron: Die API liefert sofort HTTP 202 mit einer batch_id, der Abschluss wird über Batch-Status-Polling, einen Webhook-Callback oder eine E-Mail-Benachrichtigung signalisiert, und die Batch-Status-Antwort enthält eine vorsignierte Download-URL für das fertige ZIP. Erfordert einen kostenpflichtigen Plan und einen privaten API-Key.


Endpunkt#

POST /v1/convert/website-to-pdf

Content-Type: application/json

Ausgabeformat: ZIP-Archiv mit einer PDF-Datei pro gefundener Seite.

Modus: Immer asynchron. Liefert sofort HTTP 202.


Authentifizierung#

Dieser Endpunkt erfordert einen privaten API-Key. Öffentliche Keys werden für die Website-Erfassung nicht unterstützt.

X-API-Key: sk_your_private_key

Request-Parameter#

Website-Erkennungsparameter#

Parameter Typ Erforderlich Standard Beschreibung Plan-Freigabe
url string Ja -- Die Basis-URL der Website (z. B. https://example.com). Wird als Wurzel für die Seitenerkennung verwendet. --
crawl_mode string Nein "auto" Methode zur URL-Erkennung. Einer von "auto", "sitemap" oder "full". Siehe Crawl-Modi weiter unten. Sitemap erfordert Indie+, Full erfordert Studio+
include_patterns string[] Nein null Regex-Muster zum Whitelisten gefundener URLs. Wird nur im full-Crawl-Modus verwendet. --
exclude_patterns string[] Nein Systemstandards Regex-Muster zum Blacklisten von URLs. Wird nur im full-Crawl-Modus verwendet. Wenn weggelassen, werden integrierte Standardwerte verwendet, die statische Assets, Login-/Admin-/Warenkorb-Seiten und tiefe Paginierung ausschließen. --

Benachrichtigungsparameter#

Parameter Typ Erforderlich Standard Beschreibung Plan-Freigabe
output_filename string Nein Automatisch generiert Benutzerdefinierter Basisname für die ausgegebene ZIP-Datei. Der Zeitstempel wird automatisch angehängt. --
notification_email string Nein E-Mail des Projektinhabers E-Mail-Adresse, die bei Abschluss des Jobs benachrichtigt wird. --
callback_url string Nein -- Webhook-URL, die bei Abschluss einen POST-Request erhält. Erfordert Webhook-Zugriff

Browser- und Rendering-Parameter#

Diese Einstellungen gelten für die Konvertierung jeder einzelnen Seite innerhalb der Website.

Parameter Typ Erforderlich Standard Beschreibung Plan-Freigabe
viewport_width integer Nein 1920 Breite des Browser-Viewports in Pixeln. --
viewport_height integer Nein 1080 Höhe des Browser-Viewports in Pixeln. --
single_page boolean Nein true true rendert jede Seite als eine durchgehende PDF-Seite. false erzeugt paginierte Ausgabe anhand der Seitengröße aus pdf_options. --
load_media boolean Nein true Wartet vor der Konvertierung, bis alle Bilder und Videos vollständig geladen sind. --
enable_scroll boolean Nein true Scrollt jede Seite, um Lazy-Loading-Inhalte auszulösen. --
handle_sticky_header boolean Nein true Erkennt Sticky-/Fixed-Header und behandelt sie vor der Erfassung. --
handle_cookies boolean Nein true Blendet Cookie-Consent-Banner automatisch aus. --
wait_for_images boolean Nein true Wartet, bis alle <img>-Elemente fertig geladen sind. --
wait_for_selector string Nein null CSS-Selektor, auf den vor der Aufnahme gewartet wird, angewendet auf jede Seite. Gibt 422 zurück, wenn er nicht innerhalb von wait_for_selector_timeout erscheint. Nützlich für SPAs, die Inhalte nach dem Laden hydrieren. --
wait_for_selector_timeout integer Nein 10000 Millisekunden, die auf wait_for_selector gewartet wird (maximal 60000). --
block_ads boolean Nein false Bricht Anfragen an bekannte Werbe-/Tracker-Domains ab, sodass diese nie geladen, gerendert werden oder die Aufnahme verlangsamen. --
block_media boolean Nein false Bricht Bild- und Audio-/Videoanfragen vollständig ab, für ein schnelleres, leichteres Rendering. Anders als load_media (das nur das Warten steuert), verhindert dies das Herunterladen von Medien vollständig. --

Authentifizierung und benutzerdefinierte Requests#

Parameter Typ Erforderlich Standard Beschreibung Plan-Freigabe
auth object Nein null HTTP-Basic-Auth-Zugangsdaten, die auf jede Seite angewendet werden. Format: {"username": "...", "password": "..."}. Erfordert Basic-Auth-Zugriff
cookies array Nein null Array von Cookie-Objekten, die vor jedem Seitenaufruf injiziert werden. Maximal 50 Cookies. Erfordert Basic-Auth-Zugriff
headers object Nein null Benutzerdefinierte HTTP-Header, die mit jedem Request gesendet werden. Maximal 20 Header. Erfordert Basic-Auth-Zugriff

PDF-Optionen#

Übergib diese innerhalb eines pdf_options-Objekts. Sie gelten für jede Seite der Website.

Parameter Typ Standard Beschreibung
page_size string "A4" Benannte Seitengröße. Wird ignoriert, wenn sowohl page_width als auch page_height gesetzt sind.
page_width float null Benutzerdefinierte Seitenbreite in Millimetern. page_width und page_height müssen gemeinsam gesetzt werden.
page_height float null Benutzerdefinierte Seitenhöhe in Millimetern.
orientation string "portrait" "portrait" oder "landscape".
margins object {"top": 10, "bottom": 10, "left": 10, "right": 10} Seitenränder in Millimetern.
scale float 1.0 Skalierungsfaktor für den Inhalt. Bereich: 0.1 bis 2.0. Nur im paginierten Modus.
grayscale boolean false Konvertiert jede PDF-Seite in Graustufen.
header object null Seitenkopf für den paginierten Modus. Format: {"content": "<html>", "height": 15}. Unterstützt Template-Variablen: {{page}}, {{total_pages}}, {{date}}, {{title}}, {{url}}.
footer object null Seitenfuß für den paginierten Modus. Gleiches Format wie beim Header.

Unterstützte Seitengrößen: A0, A1, A2, A3, A4, A5, A6, B0, B1, B2, B3, B4, B5, Letter, Legal, Tabloid, Ledger


Crawl-Modi#

"auto" (Standard)#

Verwendet den höchsten Crawl-Modus, den dein Plan erlaubt. Wenn dein Plan vollständiges Crawling unterstützt, wird ein vollständiger Crawl ausgeführt. Wenn dein Plan nur Sitemap unterstützt, wird die Sitemap-Erkennung ausgeführt.

"sitemap"#

Erkennt Seiten, indem die sitemap.xml der Website geparst wird:

  1. Ruft {base_url}/sitemap.xml ab (30-Sekunden-Timeout)
  2. Wenn das Root-Element <sitemapindex> ist, werden alle untergeordneten Sitemaps rekursiv abgerufen
  3. Extrahiert alle <url><loc>-Einträge aus <urlset>-Elementen
  4. Gibt die vollständige Liste der gefundenen URLs zurück

Gibt einen Fehler zurück, wenn die Sitemap fehlt, einen Nicht-200-Status liefert, ungültiges XML enthält oder keine URLs enthält.

"full"#

Führt einen umfassenden zweiphasigen Crawl durch:

Phase 1 -- Seed-Erkennung:

  1. Parst robots.txt nach Sitemap-Direktiven und Crawl-Regeln
  2. Prüft Standard-Sitemap-Pfade (/sitemap.xml, /wp-sitemap.xml, /sitemap_index.xml usw.)
  3. Findet RSS/Atom-Feeds über <link>-Tags und gängige Feed-Pfade
  4. Extrahiert Seed-URLs aus allen gefundenen Quellen

Phase 2 -- Breadth-First-Link-Crawl:

  1. Startet bei der Basis-URL sowie allen Seed-URLs
  2. Besucht jede Seite und reiht Links derselben Domain in die Warteschlange ein
  3. Wendet include_patterns und exclude_patterns an, um Links zu filtern
  4. Beachtet die Regeln von robots.txt
  5. Erkennt und vermeidet unendliche URL-Fallen (Kalenderseiten, facettierte Filter usw.)
  6. Dedupliziert URLs durch Normalisieren von Schema, Host und Query-Parametern sowie Entfernen von Tracking-Parametern (utm_*, fbclid, gclid usw.)

Standard-Exclude-Muster (wenn exclude_patterns nicht angegeben wird):

  • Statische Assets: *.pdf, *.zip, *.jpg, *.png, *.gif, *.svg, *.css, *.js, *.xml, *.json, *.mp4, *.webm, *.woff, *.woff2
  • Geschützte Pfade: /login, /admin, /cart, /checkout
  • Tiefe Paginierung: URLs mit page=-Parametern mit mehr als 3 Stellen

Antwort#

202 Accepted (sofort)#

{
    "status": "processing",
    "batch_id": "550e8400-e29b-41d4-a716-446655440000",
    "url_count": 42,
    "total_discovered": 42,
    "discovery_method": "sitemap",
    "output_format": "zip"
}
Feld Beschreibung
batch_id UUID zur Nachverfolgung des Jobs über Batch-Status-Polling oder Webhook.
url_count Anzahl der Seiten, die konvertiert werden.
total_discovered Gesamtzahl der vom Crawl gefundenen Seiten.
discovery_method "sitemap" oder "full_crawl", abhängig vom effektiven Crawl-Modus.

Batch-Status-Polling#

Fragt mit der batch_id aus der 202-Antwort ab:

GET /v1/convert/batch/{batch_id}
X-API-Key: sk_your_private_key

Liefert den Gesamtstatus, Status pro URL sowie bei Abschluss eine vorsignierte Download-URL für das ZIP. Das vollständige Antwortschema findest du unter Batch-Status-Polling.

Webhook-Callback-Payload#

Wenn callback_url angegeben ist, sendet EnConvert bei Abschluss einen POST-Request:

{
    "job_id": "batch-uuid",
    "status": "success",
    "batch_id": "550e8400-e29b-41d4-a716-446655440000",
    "gcs_uri": "env/files/{project_id}/url-to-pdf/website_20260405_123456789.zip",
    "filename": "website_20260405_123456789.zip",
    "file_size": 12345678,
    "total_tasks": 42,
    "successful_tasks": 40,
    "failed_tasks": 2,
    "tasks": [
        {"url": "https://example.com/", "status": "success", "filename": "example_20260405_001.pdf"},
        {"url": "https://example.com/about", "status": "success", "filename": "example_20260405_002.pdf"},
        {"url": "https://example.com/broken", "status": "failed", "error": "Timeout"}
    ]
}

E-Mail-Benachrichtigung#

Bei Abschluss des Jobs wird eine E-Mail an notification_email gesendet (standardmäßig an die E-Mail-Adresse des Projektinhabers), unabhängig davon, ob der Job erfolgreich war oder fehlgeschlagen ist.


Freigabe nach Abo-Plan#

Funktion Founding Indie Studio Enterprise
Website-Erfassung Nein Ja Ja Ja
Sitemap-Crawl-Modus Nein Ja Ja Ja
Full-Crawl-Modus Nein Nein Ja Ja
Webhook-Callbacks Nein Nein Ja Ja
HTTP Basic Auth Nein Ja Ja Ja
Cookie-Injektion Nein Ja Ja Ja
Benutzerdefinierte Header Nein Ja Ja Ja
Batch-Größenlimit 0 Planabhängig Planabhängig Unbegrenzt
Monatliche Konvertierungen 100 Planabhängig Planabhängig Unbegrenzt
Founding-Plan: Die Website-Erfassung ist im Founding-Plan nicht verfügbar. Der Versuch, diesen Endpunkt zu nutzen, liefert 403 Forbidden.

Code-Beispiele#

Python (Privater API-Key)#

import requests
import time

# Start the website capture
response = requests.post(
    "https://api.enconvert.com/v1/convert/website-to-pdf",
    headers={"X-API-Key": "sk_your_private_key"},
    json={
        "url": "https://example.com",
        "crawl_mode": "sitemap",
        "output_filename": "example-website",
        "pdf_options": {
            "page_size": "A4",
            "orientation": "portrait"
        }
    }
)

data = response.json()
print(f"Batch ID: {data['batch_id']}")
print(f"Pages found: {data['url_count']}")

# Poll for completion
batch_id = data["batch_id"]
while True:
    status = requests.get(
        f"https://api.enconvert.com/v1/convert/batch/{batch_id}",
        headers={"X-API-Key": "sk_your_private_key"}
    ).json()

    print(f"Status: {status['status']} ({status['completed']}/{status['total']})")

    if status["status"] in ("completed", "partial", "failed"):
        if status.get("zip_download_url"):
            print(f"Download: {status['zip_download_url']}")
        break

    time.sleep(5)

PHP (Privater API-Key)#

$ch = curl_init("https://api.enconvert.com/v1/convert/website-to-pdf");
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        "Content-Type: application/json",
        "X-API-Key: sk_your_private_key"
    ],
    CURLOPT_POSTFIELDS => json_encode([
        "url" => "https://example.com",
        "crawl_mode" => "sitemap",
        "output_filename" => "example-website",
        "pdf_options" => [
            "page_size" => "A4",
            "orientation" => "portrait"
        ]
    ])
]);

$response = json_decode(curl_exec($ch), true);
curl_close($ch);

echo "Batch ID: " . $response["batch_id"] . "\n";
echo "Pages found: " . $response["url_count"] . "\n";

Node.js (Privater API-Key)#

const response = await fetch("https://api.enconvert.com/v1/convert/website-to-pdf", {
    method: "POST",
    headers: {
        "Content-Type": "application/json",
        "X-API-Key": "sk_your_private_key"
    },
    body: JSON.stringify({
        url: "https://example.com",
        crawl_mode: "sitemap",
        output_filename: "example-website",
        pdf_options: {
            page_size: "A4",
            orientation: "portrait"
        }
    })
});

const data = await response.json();
console.log(`Batch ID: ${data.batch_id}`);
console.log(`Pages found: ${data.url_count}`);

// Poll for completion
const poll = async () => {
    const status = await fetch(
        `https://api.enconvert.com/v1/convert/batch/${data.batch_id}`,
        { headers: { "X-API-Key": "sk_your_private_key" } }
    ).then(r => r.json());

    console.log(`Status: ${status.status} (${status.completed}/${status.total})`);

    if (["completed", "partial", "failed"].includes(status.status)) {
        if (status.zip_download_url) console.log(`Download: ${status.zip_download_url}`);
        return;
    }
    setTimeout(poll, 5000);
};
poll();

Go (Privater API-Key)#

package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "net/http"
)

func main() {
    body, _ := json.Marshal(map[string]interface{}{
        "url":             "https://example.com",
        "crawl_mode":      "sitemap",
        "output_filename": "example-website",
        "pdf_options": map[string]interface{}{
            "page_size":   "A4",
            "orientation": "portrait",
        },
    })

    req, _ := http.NewRequest("POST", "https://api.enconvert.com/v1/convert/website-to-pdf", bytes.NewBuffer(body))
    req.Header.Set("Content-Type", "application/json")
    req.Header.Set("X-API-Key", "sk_your_private_key")

    resp, _ := http.DefaultClient.Do(req)
    defer resp.Body.Close()

    respBody, _ := io.ReadAll(resp.Body)
    fmt.Println(string(respBody))
}

Mit Webhook-Callback#

{
    "url": "https://example.com",
    "crawl_mode": "full",
    "callback_url": "https://your-server.com/webhook/enconvert",
    "output_filename": "example-full-site",
    "include_patterns": [".*\\/blog\\/.*", ".*\\/docs\\/.*"],
    "pdf_options": {
        "page_size": "Letter",
        "margins": {"top": 20, "bottom": 20, "left": 15, "right": 15}
    }
}

Mit Authentifizierung (passwortgeschützte Website)#

{
    "url": "https://staging.example.com",
    "crawl_mode": "sitemap",
    "auth": {
        "username": "admin",
        "password": "staging-password"
    },
    "cookies": [
        {"name": "session_token", "value": "abc123", "domain": "staging.example.com"}
    ]
}

Fehlerantworten#

Status Bedingung
400 Bad Request Fehlender oder leerer url-Parameter
400 Bad Request Keine URLs in der Sitemap gefunden
400 Bad Request Timeout beim Abrufen der Sitemap (30-Sekunden-Limit)
400 Bad Request Nicht-200-Antwort von der Sitemap-URL
400 Bad Request Ungültiges XML in der Sitemap
400 Bad Request Nicht erkanntes Sitemap-Format
400 Bad Request Keine Seiten gefunden (Full Crawl hat null URLs gefunden)
400 Bad Request Ungültige Struktur von auth, cookies oder headers
402 Payment Required Monatliches Ops-Kontingent durch Anzahl gefundener Seiten überschritten
402 Payment Required Speicherlimit erreicht
403 Forbidden Website-Crawling im aktuellen Plan nicht verfügbar (Founding-Plan)
403 Forbidden Full-Crawl-Modus erfordert Studio-Plan oder höher
403 Forbidden Anzahl gefundener Seiten überschreitet das Batch-Größenlimit
403 Forbidden Funktion im Plan nicht verfügbar (Webhook, Basic Auth)
500 Internal Server Error Fehler beim Crawlen oder Konvertieren

Limits#

Limit Wert
Sitemap-Abruf-Timeout 30 Sekunden
Globales Crawl-Timeout (Full-Modus) 10 Minuten
Maximale Crawl-Tiefe (Full-Modus) 10 Ebenen
Crawl-Timeout pro Seite (Full-Modus) 30 Sekunden
Speicherlimit des Crawlers 512 MB
Schwellenwert für Endlos-Fallen 20 URLs pro URL-Muster
Robots.txt-Abruf-Timeout 10 Sekunden
Maximale Seiten pro Crawl Batch-Größenlimit des Plans
Maximale Cookies pro Request 50
Maximale benutzerdefinierte Header pro Request 20
Webhook-Zustellungs-Timeout 30 Sekunden
Monatliche Konvertierungen Planabhängig
Aufbewahrungsdauer der Dateien Planabhängig

Häufig gestellte Fragen#

Wie konvertiere ich eine ganze Website mit einer API in PDF?#

Sende einen POST-Request an /v1/convert/website-to-pdf mit der Basis-url der Website und deinem privaten Key im X-API-Key-Header. Die API findet jede Seite (Sitemap oder Full Crawl), konvertiert jede davon in PDF, bündelt sie in einem ZIP und liefert HTTP 202 mit einer batch_id, die du für den Download-Link abfragen kannst.

Was ist der Unterschied zwischen Sitemap- und Full-Crawl-Modus?#

crawl_mode: "sitemap" parst die sitemap.xml der Website (einschließlich verschachtelter Sitemap-Indizes) und ist ab dem Indie-Plan verfügbar. crawl_mode: "full" führt einen zweiphasigen Crawl aus: zuerst Seed-Erkennung über robots.txt, Sitemaps und RSS/Atom-Feeds, danach ein Breadth-First-Link-Crawl innerhalb derselben Domain mit Filterung durch include_patterns/exclude_patterns. Dieser Modus erfordert Studio oder höher. Der Standard "auto" verwendet den höchsten Modus, den dein Plan erlaubt.

Woran erkenne ich, dass mein Website-zu-PDF-Job abgeschlossen ist?#

Frage GET /v1/convert/batch/{batch_id} mit deinem privaten Key ab, um den Gesamtstatus, Status pro URL und eine vorsignierte ZIP-Download-URL zu erhalten, oder übergib eine callback_url, um bei Abschluss einen Webhook-POST zu erhalten. Zusätzlich wird bei Abschluss eine E-Mail an notification_email (standardmäßig an den Projektinhaber) gesendet, unabhängig davon, ob der Job erfolgreich war oder fehlgeschlagen ist.

Kann ich eine passwortgeschützte Website oder eine Staging-Website als PDF archivieren?#

Ja, auf Plänen mit Basic-Auth-Zugriff: Übergib auth mit username und password für HTTP Basic Auth, das auf jede Seite angewendet wird, injiziere bis zu 50 Sitzungs-cookies oder sende bis zu 20 benutzerdefinierte headers.

Warum liefert der Website-zu-PDF-Endpunkt 403 Forbidden?#

Die häufigsten Ursachen: Die Website-Erfassung ist im Founding-Plan nicht verfügbar, crawl_mode: "full" erfordert Studio oder höher, die Anzahl gefundener Seiten überschreitet das Batch-Größenlimit deines Plans, oder eine angeforderte Funktion (Webhook, Basic Auth) ist in deinem Plan nicht enthalten.