---
seo_title: Website zu PDF API | Ganze Website als PDF crawlen | EnConvert
meta_desc: Crawle eine ganze Website und konvertiere jede Seite in PDF mit POST /v1/convert/website-to-pdf. Sitemap- oder Full-Crawl, ZIP-Ausgabe, asynchron per Webhook.
keywords: ganze website als pdf sichern api, website crawler pdf api, alle seiten einer website als pdf exportieren, sitemap zu pdf konvertieren api, webseite komplett als pdf archivieren, website pdf export automatisieren, bulk website zu pdf konverter api, gesamte webseite programmatisch als pdf speichern
---

# 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](#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)

```json
{
    "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](/de/docs/endpoints/convert/web-pages/url-to-pdf.md#batch-status-polling-private-keys-only).

### Webhook-Callback-Payload

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

```json
{
    "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 |

<div class="alert alert-warning">
<strong>Founding-Plan:</strong> Die Website-Erfassung ist im Founding-Plan nicht verfügbar. Der Versuch, diesen Endpunkt zu nutzen, liefert <code>403 Forbidden</code>.
</div>

---

## Code-Beispiele

### Python (Privater API-Key)

```python
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)

```php
$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)

```javascript
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)

```go
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

```json
{
    "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)

```json
{
    "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.
