---
type: "firecrawl-provider"
description: "Any open documentation site hosted on Read the Docs at <project>.readthedocs.io (Sphinx, MkDocs, Jupyter Book and more): project metadata with every active version and translation, the platform's server-side full-text docs search with section hits, any page as clean Markdown with its heading outline, and the Sphinx or MkDocs page index of a version. Public per-site endpoints only; no login or key."
use_when: "Any open documentation site hosted on Read the Docs at <project>.readthedocs.io (Sphinx, MkDocs, Jupyter Book and more): project metadata with every active version and translation, the platform's server-side full-text docs search with section hits, any page as clean Markdown with its heading outline, and the Sphinx or MkDocs page index of a version. Public per-site endpoints only; no login or key."
categories: "Developer"
capabilities: 4
credits_per_call: 5
---
# Read the Docs on Firecrawl Alexandria

Any open documentation site hosted on Read the Docs at <project>.readthedocs.io (Sphinx, MkDocs, Jupyter Book and more): project metadata with every active version and translation, the platform's server-side full-text docs search with section hits, any page as clean Markdown with its heading outline, and the Sphinx or MkDocs page index of a version. Public per-site endpoints only; no login or key.

- Categories: Developer
- Category index: [Developer category](https://firecrawl.dev/alexandria/agents/categories/developer)
- Provider key: `readthedocs-io`
- Access: Firecrawl credits
- Cost: 5 credits per call

## More

- [Human guide](https://firecrawl.dev/app/alexandria/readthedocs-io)
- [OpenAPI spec](https://firecrawl.dev/alexandria/agents/providers/readthedocs-io/openapi.json)

## Capabilities

- [Get page](https://firecrawl.dev/alexandria/agents/providers/readthedocs-io/developer-documentation/get_page): One Read the Docs page as Markdown, from the Markdown the platform serves to agents (GET <page> with Accept: text/markdown): url, project, title, description, the heading outline (level, text, anchor) and the page content from its first title, without the theme's navigation sidebar, the On this page table and heading permalink marks, plus the project name, version and build time from the addons API. section (or a URL #anchor) returns one heading subtree or one Sphinx API definition such as Page.get_text, so very large reference pages can be read piece by piece. Takes a pasted URL, or project plus path (relative to the version root, or from the site root as search_docs returns it) and optional version. max_chars truncates. Missing pages and sections are not_found.
- [Get project](https://firecrawl.dev/alexandria/agents/providers/readthedocs-io/developer-documentation/get_project): One Read the Docs project from its per-site addons API (GET https://<project>.readthedocs.io/_/addons/): slug, name, language, programming language, homepage, repository, default version and branch, docs root, versioning scheme, parent project for subprojects, every active version (slug, type, ref, hidden flag, docs root, PDF/EPUB/zip downloads) and translations. With a pasted URL, current_version is the version that URL is on. Unknown projects are not_found.
- [List pages](https://firecrawl.dev/alexandria/agents/providers/readthedocs-io/developer-documentation/list_pages): Every page of one version of a Read the Docs project, from the generator's own search index: Sphinx searchindex.js (docnames and titles, with URLs built for the html or dirhtml builder from _static/documentation_options.js) or MkDocs search/search_index.json or Zensical search.json (entries without an anchor). Returns title, path and URL per page with optional path_prefix (a section such as user-guide/) and q filters and offset paging, so a section can be listed and then read page by page with get_page. Sites built with other generators are not_found.
- [Search docs](https://firecrawl.dev/alexandria/agents/providers/readthedocs-io/developer-documentation/search_docs): Full-text search of one Read the Docs project with the platform's own search API (GET https://<project>.readthedocs.io/_/api/v3/search/?q=project:<project>/<version> <query>): ranked pages with title, URL, path, project and version, and the matching sections (anchor id, title, deep link, a 500-character content snippet and plain-text highlights). Searches the default version unless version is given; a pasted URL searches that URL's version. Paginates with page and next_page. An unknown project or version is not_found; a query with no hits is an empty result.

## 1. Choose this provider when

Any open documentation site hosted on Read the Docs at <project>.readthedocs.io (Sphinx, MkDocs, Jupyter Book and more): project metadata with every active version and translation, the platform's server-side full-text docs search with section hits, any page as clean Markdown with its heading outline, and the Sphinx or MkDocs page index of a version. Public per-site endpoints only; no login or key.

## 2. Minimal request

Call `POST https://api.firecrawl.dev/v2/scrape` with `{ alexandria: { provider, capability, options } }`. For a batch, send `{ alexandria: [...] }` with up to 10 calls.

```json
{
  "provider": "readthedocs-io",
  "capability": "developer-documentation/get_page",
  "options": {
    "url": "https://argo-cd.readthedocs.io/en/stable/user-guide/sync-waves/"
  }
}
```

## 3. Add provider options

Use only the options needed for the task:

- `max_chars` (number): Truncate content to this many characters (default 100000). Example: `500`
- `path` (string): With project: the page path relative to the version root (reference/Image.html, user-guide/sync-waves/) or from the site root when it starts with / (/en/stable/reference/Image.html, as search_docs returns). Example: `<path>`
- `project` (string): Read the Docs project slug, the <project> in https://<project>.readthedocs.io (e.g. pillow, argo-cd, pypdf, pymupdf). Pattern: ^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$. Example: `<project>`
- `section` (string): Return only this part of the page: a heading (text or anchor, case-insensitive, e.g. Modifying Pages or how-sync-waves-work) and its subsections, or a Sphinx API definition anchor (e.g. Page.get_text, PIL.Image.Image.resize) up to the next definition. Overrides a URL #anchor. Unknown sections are not_found. Example: `<section>`
- `url` (string): A page URL on https://<project>.readthedocs.io/, e.g. https://pillow.readthedocs.io/en/stable/reference/Image.html. A site-root URL follows the redirect to the default version's index. Pattern: ^[Hh][Tt][Tt][Pp][Ss]?://. Example: `<url>`
- `version` (string): Version slug as it appears in the docs URL (latest, stable, a branch or tag slug such as release-3.6 or 6.1.0). Defaults to the project's default version. Pattern: ^[A-Za-z0-9._-]{1,100}$. Example: `<version>`

## 4. Request through your preferred interface

### JavaScript

```javascript
const result = await firecrawl.scrape({
  alexandria: {
    provider: "readthedocs-io",
    capability: "developer-documentation/get_page",
    options: {
      url: "https://argo-cd.readthedocs.io/en/stable/user-guide/sync-waves/",
    },
  },
});
```

### Python

```python
result = firecrawl.scrape_alexandria({
  "provider": "readthedocs-io",
  "capability": "developer-documentation/get_page",
  "options": {
    "url": "https://argo-cd.readthedocs.io/en/stable/user-guide/sync-waves/"
  }
})
```

### cURL

```sh
curl https://api.firecrawl.dev/v2/scrape \
  -H "Authorization: Bearer $FIRECRAWL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "alexandria": {
    "provider": "readthedocs-io",
    "capability": "developer-documentation/get_page",
    "options": {
      "url": "https://argo-cd.readthedocs.io/en/stable/user-guide/sync-waves/"
    }
  }
}'
```

### CLI

```sh
firecrawl scrape 'readthedocs-io/developer-documentation/get_page' \
  --options '{"url":"https://argo-cd.readthedocs.io/en/stable/user-guide/sync-waves/"}'
```


### MCP

Call the FCX MCP retrieve tool with this object:

```json
{
  "provider": "readthedocs-io",
  "capability": "developer-documentation/get_page",
  "options": {
    "url": "https://argo-cd.readthedocs.io/en/stable/user-guide/sync-waves/"
  }
}
```

Ask for only the returned fields needed by the task.

## 5. Full request shape

```json
{
  "provider": "readthedocs-io",
  "capability": "developer-documentation/get_page",
  "options": {
    "url": "https://argo-cd.readthedocs.io/en/stable/user-guide/sync-waves/"
  }
}
```

## 6. Response data

The response includes `success`, `provider`, `capability`, `creditsCost` and `data`. This example shows the provider payload in `data`:

```json
{
  "built_at": "2026-10-20T19:30:25.762937Z",
  "chars": 11823,
  "content": "# Sync Phases and Waves\n\nSync phases and hooks define when resources are applied such as before or after the main sync operation. This makes it possible to define jobs, or any other resource to run or be applied in any specific order.\n\nArgo CD has the following hook types:\n\n| Hook | Description |\n| --- | --- |\n| `PreSync` | Executes prior to the application of the manifests. |\n| `Sync` | Executes after all `PreSync` hooks completed and were successful, at the same time as the application of the manifests. |\n| `Skip` | Indicates to Argo CD to skip the application of the manifest. |\n| `PostSync` | Executes after all `Sync` hooks completed and were successful, a successful application, and all resources in a `Healthy` state. |\n| `SyncFail` | Executes when the sync operation fails. |\n| `PreDelete` | Executes before Application resources are deleted. Only runs when the entire Application is being deleted, not during normal sync operations (even with pruning enabled. ) |\n| `PostDelete` | Executes after all Application resources are deleted. *Available starting in v2.10.* |\n\nAdding the argocd.argoproj.io/hook annotation to a resource will assign it to a specific phase. During a Sync operation, Argo CD will apply the resource during the appropriate phase of the deployment. Hooks can be any type of Kubernetes resource kind, but tend to be Pod, Job or Argo Workflows. Multiple hooks can be specified as a comma separated list.\n\n## How phases work?\n\nArgo CD will respect resources assigned to different phases, during a sync operation Argo CD will do the following:\n\n1. Apply all the resources marked as PreSync hooks. If any of them fails the whole sync process will stop and will be marked as failed\n2. Apply all the resources marked as Sync hooks. If any of them fails the whole sync process will be marked as failed. Hooks marked with SyncFail will also run\n3. Apply all the resources marked as PostSync hooks. If any of them fails the whole sync process will be marked as failed.\n\nHooks marked with Skip will not be applied.\n\nHere is a graphical overview of the sync process:\n\n![phases](https://argo-cd.readthedocs.io/en/stable/user-guide/how_phases_work.png)\n\nYou can use this simple lifecycle method in various scenarios. For example you can run an essential check as a PreSync hook. If it fails then the whole sync operation will stop preventing the deployment from taking place. In a similar manner you can run smoke tests as PostSync hooks. If they succeed you know that your application has passed the validation. If they fail then the whole deployment will be marked as failed and Argo CD can then notify you in order to take further actions.\n\nHooks do not run during a selective sync operation. During the SyncFail phase, hooks can be used for cleanup and other housekeeping tasks. If a SyncFail hook itself fails, Argo CD does not take any additional action beyond marking the overall operation as failed.\n\nDuring pruning, the wave order is reversed from the creation order. Resources in higher waves are pruned first. If pruning any resource in a wave fails, the operation is marked as failed, and resources in lower waves are not processed. This ensures that dependent resources are deleted in the correct order.\n\n## Hook lifecycle and cleanup\n\nArgo CD offers several methods to clean up hooks and decide how much history will be kept for previous runs. In the most basic case you can use the argocd.argoproj.io/hook-delete-policy to decide when a hook will be deleted. This can take the following values:\n\n| Policy | Description |\n| --- | --- |\n| `HookSucceeded` | The hook resource is deleted when the sync succeeds. For completion-based hooks such as `Job` or `Workflow`, this typically happens after the hook completes successfully. |\n| `HookFailed` | The hook resource is deleted after the hook failed. |\n| `BeforeHookCreation` | Any existing hook resource is deleted before the new one is created (since v1.3). It is meant to be used with `/metadata/name`. |\n\nNote that if no deletion policy is specified, Argo CD will automatically assume `BeforeHookCreation` rules.\n\nWhen Helm hook annotations are mapped onto Argo CD hooks, delete-policy evaluation still follows Argo CD sync phases and sync result semantics rather than Helm's per-hook-event lifecycle. For example, a `PreSync` resource mapped from Helm may remain available until later phases finish, and passive resources such as `ServiceAccount` do not have a completion state like `Job` or `Workflow`.\n\n## PreDelete and PostDelete Hooks\n\n### PreDelete Hooks\n\nPreDelete hooks execute before an Application and its resources are deleted. They run only during Application deletion (e.g., `kubectl delete application` or `argocd app delete`), not during normal sync operations, even when pruning is enabled. **Behavior:**\n\n1. When an Application is deleted, Argo CD checks for PreDelete hooks defined in the Application's manifests\n2. If PreDelete hooks exist, they are created and executed before any Application resources are deleted\n3. Argo CD waits for all PreDelete hooks to reach a Healthy state before proceeding with deletion\n4. Once all PreDelete hooks complete successfully, they are cleaned up and the Application resources are deleted\n\n**Failure Handling:**\n\nIf a PreDelete hook fails (e.g., a Job fails or a Pod crashes), the Application deletion is blocked:\n\n- The Application will remain in a deleting state with a `DeletionError` condition\n- Application resources will not be deleted until the hook succeeds\n- The user can fix the failing hook by updating its manifest in the git repository\n- After fixing the hook, Argo CD will automatically retry the deletion on the next reconciliation\n- Alternatively, the user can manually delete the failing hook resource to allow deletion to proceed\n\n### PostDelete Hooks\n\nPostDelete hooks execute after all Application resources have been deleted. They are useful for cleanup operations, notifications, or removing external resources.\n\n**Behavior:**\n\n1. Application resources are deleted first\n2. Once all Application resources are fully removed, PostDelete hooks are created and executed\n3. Argo CD waits for all PostDelete hooks to reach a Healthy state\n4. Once all PostDelete hooks complete successfully, they are cleaned up and the Application is fully removed\n\n**Failure Handling:**\n\nIf a PostDelete hook fails:\n\n- The Application is already deleted from the cluster, but the Application CR remains with a `DeletionError` condition\n- The user can fix the failing hook by updating its manifest in the git repository\n- After fixing the hook, Argo CD will automatically retry on the next reconciliation\n- Alternatively, the user can manually delete the failing hook resource to complete the Application deletion\n\n## How sync waves work?\n\nArgo CD also offers an alternative method of changing the sync order of resources. These are sync waves. They are defined by the argocd.argoproj.io/sync-wave annotation. The value is an integer that defines the ordering (ArgoCD will start deploying from the lowest number and finish with the highest number).\n\nHooks and resources are assigned to wave 0 by default. The wave can be negative, so you can create a wave that runs before all other resources.\n\nWhen a sync operation takes place, Argo CD will:\n\n1. Order all resources according to their wave (lowest to highest)\n2. Apply the resources according to the resulting sequence\n\nThere is currently a delay between each sync wave in order to give other controllers a chance to react to the spec change that was just applied. This also prevents Argo CD from assessing resource health too quickly (against the stale object), causing hooks to fire prematurely. The current delay between each sync wave is 2 seconds and can be configured via the environment variable ARGOCD\\_SYNC\\_WAVE\\_DELAY.\n\n## Combining Sync waves and hooks\n\nWhile you can use sync waves on their own, for maximum flexibility you can combine them with hooks. This way you can use sync phases for coarse grained ordering and sync waves for defining the exact order of a resource within an individual phase.\n\n![waves](https://argo-cd.readthedocs.io/en/stable/user-guide/how_waves_work.png)\n\nWhen Argo CD starts a sync, it orders the resources in the following precedence:\n\n1. The phase\n2. The wave they are in (lower values first)\n3. By kind (e.g. namespaces first and then other Kubernetes resources, followed by custom resources)\n4. By name\n\nOnce the order is defined:\n\n1. First Argo CD determines the number of the first wave to apply. This is the first number where any resource is out-of-sync or unhealthy.\n2. It applies resources in that wave.\n3. It repeats this process until all phases and waves are in-sync and healthy.\n\nBecause an application can have resources that are unhealthy in the first wave, it may be that the app can never get to healthy.\n\n## How Do I Configure Phases?\n\nPre-sync and post-sync can only contain hooks. Apply the hook annotation:\n\n```\nmetadata:\n  annotations:\n    argocd.argoproj.io/hook: PreSync\n```\n\n[Read more about hooks](https://argo-cd.readthedocs.io/en/stable/user-guide/resource_hooks/).\n\n## How Do I Configure Waves?\n\nSpecify the wave using the following annotation:\n\n```\nmetadata:\n  annotations:\n    argocd.argoproj.io/sync-wave: \"5\"\n```\n\nHooks and resources are assigned to wave zero by default. The wave can be negative, so you can create a wave that runs before all other resources.\n\n## Examples\n\n### Send message to Slack when sync completes\n\nThe following example uses the Slack API to send a Slack message when sync completes:\n\n```\napiVersion: batch/v1\nkind: Job\nmetadata:\n  generateName: app-slack-notification-\n  annotations:\n    argocd.argoproj.io/hook: PostSync\n    argocd.argoproj.io/hook-delete-policy: HookSucceeded\nspec:\n  template:\n    spec:\n      containers:\n        - name: slack-notification\n          image: curlimages/curl\n          command:\n            - curl\n            - '-X'\n            - POST\n            - '--data-urlencode'\n            - >-\n              payload={\"channel\": \"#somechannel\", \"username\": \"hello\", \"text\":\n              \"App Sync succeeded\", \"icon_emoji\": \":ghost:\"}\n            - 'https://hooks.slack.com/services/...'\n      restartPolicy: Never\n  backoffLimit: 2\n```\n\n### Initialize or migrate a database\n\nThe following example runs a db initialization/migration command before the main sync operation (also in wave -1):\n\n```\napiVersion: batch/v1\nkind: Job\nmetadata:\n  name: db-migrate\n  annotations:\n    argocd.argoproj.io/hook: PreSync\n    argocd.argoproj.io/hook-delete-policy: HookSucceeded\n    argocd.argoproj.io/sync-wave: '-1'\nspec:\n  ttlSecondsAfterFinished: 360\n  template:\n    spec:\n      containers:\n        - name: postgresql-client\n          image: 'my-postgres-data:11.5'\n          imagePullPolicy: Always\n          env:\n            - name: PGPASSWORD\n              value: admin\n            - name: POSTGRES_HOST\n              value: my_postgresql_db\n          command:\n            - psql\n            - '-h=my_postgresql_db'\n            - '-U postgres'\n            - '-f preload.sql'\n      restartPolicy: Never\n  backoffLimit: 1\n```\n\n### Work around ArgoCD sync failure\n\nUpgrading ingress-nginx controller (managed by helm) with ArgoCD 2.x sometimes fails to work resulting in:\n\n| . | . |\n| --- | --- |\n| OPERATION | Sync |\n| PHASE | Running |\n| MESSAGE | waiting for completion of hook batch/Job/ingress-nginx-admission-create |\n\n| . | . |\n| --- | --- |\n| KIND | batch/v1/Job |\n| NAMESPACE | ingress-nginx |\n| NAME | ingress-nginx-admission-create |\n| STATUS | Running |\n| HOOK | PreSync |\n| MESSAGE | Pending deletion |\n\nTo work around this, a helm user can add:\n\n```\ningress-nginx:\n  controller:\n    admissionWebhooks:\n      annotations:\n        argocd.argoproj.io/hook: Skip\n```\n\nWhich results in a successful sync.",
  "definitions": [],
  "description": null,
  "observed_at_ms": 1792696080577,
  "outline": [
    {
      "anchor": null,
      "level": 1,
      "text": "Sync Phases and Waves"
    },
    {
      "anchor": null,
      "level": 2,
      "text": "How phases work?"
    },
    {
      "anchor": null,
      "level": 2,
      "text": "Hook lifecycle and cleanup"
    },
    {
      "anchor": null,
      "level": 2,
      "text": "PreDelete and PostDelete Hooks"
    },
    {
      "anchor": null,
      "level": 3,
      "text": "PreDelete Hooks"
    },
    {
      "anchor": null,
      "level": 3,
      "text": "PostDelete Hooks"
    },
    {
      "anchor": null,
      "level": 2,
      "text": "How sync waves work?"
    },
    {
      "anchor": null,
      "level": 2,
      "text": "Combining Sync waves and hooks"
    },
    {
      "anchor": null,
      "level": 2,
      "text": "How Do I Configure Phases?"
    },
    {
      "anchor": null,
      "level": 2,
      "text": "How Do I Configure Waves?"
    },
    {
      "anchor": null,
      "level": 2,
      "text": "Examples"
    },
    {
      "anchor": null,
      "level": 3,
      "text": "Send message to Slack when sync completes"
    },
    {
      "anchor": null,
      "level": 3,
      "text": "Initialize or migrate a database"
    },
    {
      "anchor": null,
      "level": 3,
      "text": "Work around ArgoCD sync failure"
    }
  ],
  "project": "argo-cd",
  "project_name": "argo-cd",
  "section": null,
  "title": "Sync Phases and Waves",
  "truncated": false,
  "url": "https://argo-cd.readthedocs.io/en/stable/user-guide/sync-waves/",
  "version": "stable"
}
```

## API reference-derived contract

The following capability contract is generated from the same normalized Alexandria API reference exposed in the API spec.

### Get page

- Capability: `developer-documentation/get_page`
- Description: One Read the Docs page as Markdown, from the Markdown the platform serves to agents (GET <page> with Accept: text/markdown): url, project, title, description, the heading outline (level, text, anchor) and the page content from its first title, without the theme's navigation sidebar, the On this page table and heading permalink marks, plus the project name, version and build time from the addons API. section (or a URL #anchor) returns one heading subtree or one Sphinx API definition such as Page.get_text, so very large reference pages can be read piece by piece. Takes a pasted URL, or project plus path (relative to the version root, or from the site root as search_docs returns it) and optional version. max_chars truncates. Missing pages and sections are not_found.
- Instructions: To read a documentation page verbatim with a citable URL, for example a search_docs hit, a list_pages entry or a pasted *.readthedocs.io link. On large API pages read the outline first, then one section or definition at a time.
- Cost: 5 credits per call
- Capability file: [Get page](https://firecrawl.dev/alexandria/agents/providers/readthedocs-io/developer-documentation/get_page)

Accepted options:
- `max_chars` (number): Truncate content to this many characters (default 100000). Example: `500`
- `path` (string): With project: the page path relative to the version root (reference/Image.html, user-guide/sync-waves/) or from the site root when it starts with / (/en/stable/reference/Image.html, as search_docs returns). Example: `<path>`
- `project` (string): Read the Docs project slug, the <project> in https://<project>.readthedocs.io (e.g. pillow, argo-cd, pypdf, pymupdf). Pattern: ^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$. Example: `<project>`
- `section` (string): Return only this part of the page: a heading (text or anchor, case-insensitive, e.g. Modifying Pages or how-sync-waves-work) and its subsections, or a Sphinx API definition anchor (e.g. Page.get_text, PIL.Image.Image.resize) up to the next definition. Overrides a URL #anchor. Unknown sections are not_found. Example: `<section>`
- `url` (string): A page URL on https://<project>.readthedocs.io/, e.g. https://pillow.readthedocs.io/en/stable/reference/Image.html. A site-root URL follows the redirect to the default version's index. Pattern: ^[Hh][Tt][Tt][Pp][Ss]?://. Example: `<url>`
- `version` (string): Version slug as it appears in the docs URL (latest, stable, a branch or tag slug such as release-3.6 or 6.1.0). Defaults to the project's default version. Pattern: ^[A-Za-z0-9._-]{1,100}$. Example: `<version>`

Response schema example:
```json
{
  "built_at": "2026-10-20T19:30:25.762937Z",
  "chars": 11823,
  "content": "# Sync Phases and Waves\n\nSync phases and hooks define when resources are applied such as before or after the main sync operation. This makes it possible to define jobs, or any other resource to run or be applied in any specific order.\n\nArgo CD has the following hook types:\n\n| Hook | Description |\n| --- | --- |\n| `PreSync` | Executes prior to the application of the manifests. |\n| `Sync` | Executes after all `PreSync` hooks completed and were successful, at the same time as the application of the manifests. |\n| `Skip` | Indicates to Argo CD to skip the application of the manifest. |\n| `PostSync` | Executes after all `Sync` hooks completed and were successful, a successful application, and all resources in a `Healthy` state. |\n| `SyncFail` | Executes when the sync operation fails. |\n| `PreDelete` | Executes before Application resources are deleted. Only runs when the entire Application is being deleted, not during normal sync operations (even with pruning enabled. ) |\n| `PostDelete` | Executes after all Application resources are deleted. *Available starting in v2.10.* |\n\nAdding the argocd.argoproj.io/hook annotation to a resource will assign it to a specific phase. During a Sync operation, Argo CD will apply the resource during the appropriate phase of the deployment. Hooks can be any type of Kubernetes resource kind, but tend to be Pod, Job or Argo Workflows. Multiple hooks can be specified as a comma separated list.\n\n## How phases work?\n\nArgo CD will respect resources assigned to different phases, during a sync operation Argo CD will do the following:\n\n1. Apply all the resources marked as PreSync hooks. If any of them fails the whole sync process will stop and will be marked as failed\n2. Apply all the resources marked as Sync hooks. If any of them fails the whole sync process will be marked as failed. Hooks marked with SyncFail will also run\n3. Apply all the resources marked as PostSync hooks. If any of them fails the whole sync process will be marked as failed.\n\nHooks marked with Skip will not be applied.\n\nHere is a graphical overview of the sync process:\n\n![phases](https://argo-cd.readthedocs.io/en/stable/user-guide/how_phases_work.png)\n\nYou can use this simple lifecycle method in various scenarios. For example you can run an essential check as a PreSync hook. If it fails then the whole sync operation will stop preventing the deployment from taking place. In a similar manner you can run smoke tests as PostSync hooks. If they succeed you know that your application has passed the validation. If they fail then the whole deployment will be marked as failed and Argo CD can then notify you in order to take further actions.\n\nHooks do not run during a selective sync operation. During the SyncFail phase, hooks can be used for cleanup and other housekeeping tasks. If a SyncFail hook itself fails, Argo CD does not take any additional action beyond marking the overall operation as failed.\n\nDuring pruning, the wave order is reversed from the creation order. Resources in higher waves are pruned first. If pruning any resource in a wave fails, the operation is marked as failed, and resources in lower waves are not processed. This ensures that dependent resources are deleted in the correct order.\n\n## Hook lifecycle and cleanup\n\nArgo CD offers several methods to clean up hooks and decide how much history will be kept for previous runs. In the most basic case you can use the argocd.argoproj.io/hook-delete-policy to decide when a hook will be deleted. This can take the following values:\n\n| Policy | Description |\n| --- | --- |\n| `HookSucceeded` | The hook resource is deleted when the sync succeeds. For completion-based hooks such as `Job` or `Workflow`, this typically happens after the hook completes successfully. |\n| `HookFailed` | The hook resource is deleted after the hook failed. |\n| `BeforeHookCreation` | Any existing hook resource is deleted before the new one is created (since v1.3). It is meant to be used with `/metadata/name`. |\n\nNote that if no deletion policy is specified, Argo CD will automatically assume `BeforeHookCreation` rules.\n\nWhen Helm hook annotations are mapped onto Argo CD hooks, delete-policy evaluation still follows Argo CD sync phases and sync result semantics rather than Helm's per-hook-event lifecycle. For example, a `PreSync` resource mapped from Helm may remain available until later phases finish, and passive resources such as `ServiceAccount` do not have a completion state like `Job` or `Workflow`.\n\n## PreDelete and PostDelete Hooks\n\n### PreDelete Hooks\n\nPreDelete hooks execute before an Application and its resources are deleted. They run only during Application deletion (e.g., `kubectl delete application` or `argocd app delete`), not during normal sync operations, even when pruning is enabled. **Behavior:**\n\n1. When an Application is deleted, Argo CD checks for PreDelete hooks defined in the Application's manifests\n2. If PreDelete hooks exist, they are created and executed before any Application resources are deleted\n3. Argo CD waits for all PreDelete hooks to reach a Healthy state before proceeding with deletion\n4. Once all PreDelete hooks complete successfully, they are cleaned up and the Application resources are deleted\n\n**Failure Handling:**\n\nIf a PreDelete hook fails (e.g., a Job fails or a Pod crashes), the Application deletion is blocked:\n\n- The Application will remain in a deleting state with a `DeletionError` condition\n- Application resources will not be deleted until the hook succeeds\n- The user can fix the failing hook by updating its manifest in the git repository\n- After fixing the hook, Argo CD will automatically retry the deletion on the next reconciliation\n- Alternatively, the user can manually delete the failing hook resource to allow deletion to proceed\n\n### PostDelete Hooks\n\nPostDelete hooks execute after all Application resources have been deleted. They are useful for cleanup operations, notifications, or removing external resources.\n\n**Behavior:**\n\n1. Application resources are deleted first\n2. Once all Application resources are fully removed, PostDelete hooks are created and executed\n3. Argo CD waits for all PostDelete hooks to reach a Healthy state\n4. Once all PostDelete hooks complete successfully, they are cleaned up and the Application is fully removed\n\n**Failure Handling:**\n\nIf a PostDelete hook fails:\n\n- The Application is already deleted from the cluster, but the Application CR remains with a `DeletionError` condition\n- The user can fix the failing hook by updating its manifest in the git repository\n- After fixing the hook, Argo CD will automatically retry on the next reconciliation\n- Alternatively, the user can manually delete the failing hook resource to complete the Application deletion\n\n## How sync waves work?\n\nArgo CD also offers an alternative method of changing the sync order of resources. These are sync waves. They are defined by the argocd.argoproj.io/sync-wave annotation. The value is an integer that defines the ordering (ArgoCD will start deploying from the lowest number and finish with the highest number).\n\nHooks and resources are assigned to wave 0 by default. The wave can be negative, so you can create a wave that runs before all other resources.\n\nWhen a sync operation takes place, Argo CD will:\n\n1. Order all resources according to their wave (lowest to highest)\n2. Apply the resources according to the resulting sequence\n\nThere is currently a delay between each sync wave in order to give other controllers a chance to react to the spec change that was just applied. This also prevents Argo CD from assessing resource health too quickly (against the stale object), causing hooks to fire prematurely. The current delay between each sync wave is 2 seconds and can be configured via the environment variable ARGOCD\\_SYNC\\_WAVE\\_DELAY.\n\n## Combining Sync waves and hooks\n\nWhile you can use sync waves on their own, for maximum flexibility you can combine them with hooks. This way you can use sync phases for coarse grained ordering and sync waves for defining the exact order of a resource within an individual phase.\n\n![waves](https://argo-cd.readthedocs.io/en/stable/user-guide/how_waves_work.png)\n\nWhen Argo CD starts a sync, it orders the resources in the following precedence:\n\n1. The phase\n2. The wave they are in (lower values first)\n3. By kind (e.g. namespaces first and then other Kubernetes resources, followed by custom resources)\n4. By name\n\nOnce the order is defined:\n\n1. First Argo CD determines the number of the first wave to apply. This is the first number where any resource is out-of-sync or unhealthy.\n2. It applies resources in that wave.\n3. It repeats this process until all phases and waves are in-sync and healthy.\n\nBecause an application can have resources that are unhealthy in the first wave, it may be that the app can never get to healthy.\n\n## How Do I Configure Phases?\n\nPre-sync and post-sync can only contain hooks. Apply the hook annotation:\n\n```\nmetadata:\n  annotations:\n    argocd.argoproj.io/hook: PreSync\n```\n\n[Read more about hooks](https://argo-cd.readthedocs.io/en/stable/user-guide/resource_hooks/).\n\n## How Do I Configure Waves?\n\nSpecify the wave using the following annotation:\n\n```\nmetadata:\n  annotations:\n    argocd.argoproj.io/sync-wave: \"5\"\n```\n\nHooks and resources are assigned to wave zero by default. The wave can be negative, so you can create a wave that runs before all other resources.\n\n## Examples\n\n### Send message to Slack when sync completes\n\nThe following example uses the Slack API to send a Slack message when sync completes:\n\n```\napiVersion: batch/v1\nkind: Job\nmetadata:\n  generateName: app-slack-notification-\n  annotations:\n    argocd.argoproj.io/hook: PostSync\n    argocd.argoproj.io/hook-delete-policy: HookSucceeded\nspec:\n  template:\n    spec:\n      containers:\n        - name: slack-notification\n          image: curlimages/curl\n          command:\n            - curl\n            - '-X'\n            - POST\n            - '--data-urlencode'\n            - >-\n              payload={\"channel\": \"#somechannel\", \"username\": \"hello\", \"text\":\n              \"App Sync succeeded\", \"icon_emoji\": \":ghost:\"}\n            - 'https://hooks.slack.com/services/...'\n      restartPolicy: Never\n  backoffLimit: 2\n```\n\n### Initialize or migrate a database\n\nThe following example runs a db initialization/migration command before the main sync operation (also in wave -1):\n\n```\napiVersion: batch/v1\nkind: Job\nmetadata:\n  name: db-migrate\n  annotations:\n    argocd.argoproj.io/hook: PreSync\n    argocd.argoproj.io/hook-delete-policy: HookSucceeded\n    argocd.argoproj.io/sync-wave: '-1'\nspec:\n  ttlSecondsAfterFinished: 360\n  template:\n    spec:\n      containers:\n        - name: postgresql-client\n          image: 'my-postgres-data:11.5'\n          imagePullPolicy: Always\n          env:\n            - name: PGPASSWORD\n              value: admin\n            - name: POSTGRES_HOST\n              value: my_postgresql_db\n          command:\n            - psql\n            - '-h=my_postgresql_db'\n            - '-U postgres'\n            - '-f preload.sql'\n      restartPolicy: Never\n  backoffLimit: 1\n```\n\n### Work around ArgoCD sync failure\n\nUpgrading ingress-nginx controller (managed by helm) with ArgoCD 2.x sometimes fails to work resulting in:\n\n| . | . |\n| --- | --- |\n| OPERATION | Sync |\n| PHASE | Running |\n| MESSAGE | waiting for completion of hook batch/Job/ingress-nginx-admission-create |\n\n| . | . |\n| --- | --- |\n| KIND | batch/v1/Job |\n| NAMESPACE | ingress-nginx |\n| NAME | ingress-nginx-admission-create |\n| STATUS | Running |\n| HOOK | PreSync |\n| MESSAGE | Pending deletion |\n\nTo work around this, a helm user can add:\n\n```\ningress-nginx:\n  controller:\n    admissionWebhooks:\n      annotations:\n        argocd.argoproj.io/hook: Skip\n```\n\nWhich results in a successful sync.",
  "definitions": [],
  "description": null,
  "observed_at_ms": 1792696080577,
  "outline": [
    {
      "anchor": null,
      "level": 1,
      "text": "Sync Phases and Waves"
    },
    {
      "anchor": null,
      "level": 2,
      "text": "How phases work?"
    },
    {
      "anchor": null,
      "level": 2,
      "text": "Hook lifecycle and cleanup"
    },
    {
      "anchor": null,
      "level": 2,
      "text": "PreDelete and PostDelete Hooks"
    },
    {
      "anchor": null,
      "level": 3,
      "text": "PreDelete Hooks"
    },
    {
      "anchor": null,
      "level": 3,
      "text": "PostDelete Hooks"
    },
    {
      "anchor": null,
      "level": 2,
      "text": "How sync waves work?"
    },
    {
      "anchor": null,
      "level": 2,
      "text": "Combining Sync waves and hooks"
    },
    {
      "anchor": null,
      "level": 2,
      "text": "How Do I Configure Phases?"
    },
    {
      "anchor": null,
      "level": 2,
      "text": "How Do I Configure Waves?"
    },
    {
      "anchor": null,
      "level": 2,
      "text": "Examples"
    },
    {
      "anchor": null,
      "level": 3,
      "text": "Send message to Slack when sync completes"
    },
    {
      "anchor": null,
      "level": 3,
      "text": "Initialize or migrate a database"
    },
    {
      "anchor": null,
      "level": 3,
      "text": "Work around ArgoCD sync failure"
    }
  ],
  "project": "argo-cd",
  "project_name": "argo-cd",
  "section": null,
  "title": "Sync Phases and Waves",
  "truncated": false,
  "url": "https://argo-cd.readthedocs.io/en/stable/user-guide/sync-waves/",
  "version": "stable"
}
```

### Get project

- Capability: `developer-documentation/get_project`
- Description: One Read the Docs project from its per-site addons API (GET https://<project>.readthedocs.io/_/addons/): slug, name, language, programming language, homepage, repository, default version and branch, docs root, versioning scheme, parent project for subprojects, every active version (slug, type, ref, hidden flag, docs root, PDF/EPUB/zip downloads) and translations. With a pasted URL, current_version is the version that URL is on. Unknown projects are not_found.
- Instructions: Start here to learn which versions and translations a Read the Docs project publishes, its default version, its source repository, or the offline PDF, EPUB or zipped HTML build of a version, before searching or reading a specific version.
- Cost: 5 credits per call
- Capability file: [Get project](https://firecrawl.dev/alexandria/agents/providers/readthedocs-io/developer-documentation/get_project)

Accepted options:
- `project` (string): Read the Docs project slug, the <project> in https://<project>.readthedocs.io (e.g. pillow, argo-cd, pypdf, pymupdf). Pattern: ^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$. Example: `<project>`
- `url` (string): Alternatively any page URL on https://<project>.readthedocs.io/; the project (and, where the function uses it, the version) is read from it. Exactly one of project or url. Pattern: ^[Hh][Tt][Tt][Pp][Ss]?://. Example: `<url>`

Response schema example:
```json
{
  "current_version": null,
  "observed_at_ms": 1792696060248,
  "project": {
    "created": "2014-10-01T19:19:11.351761Z",
    "default_branch": "main",
    "default_version": "stable",
    "documentation_url": "https://pillow.readthedocs.io/en/stable/",
    "homepage": "https://python-pillow.org",
    "language": {
      "code": "en",
      "name": "English"
    },
    "modified": "2026-08-26T18:14:18.605521Z",
    "name": "Pillow",
    "programming_language": {
      "code": "py",
      "name": "Python"
    },
    "repository_url": "https://github.com/python-pillow/Pillow.git",
    "single_version": false,
    "slug": "pillow",
    "subproject_of": null,
    "translation_of": null,
    "versioning_scheme": "multiple_versions_with_translations"
  },
  "site_url": "https://pillow.readthedocs.io/",
  "translations": [],
  "versions": [
    {
      "documentation_url": "https://pillow.readthedocs.io/en/stable/",
      "downloads": {
        "epub": null,
        "htmlzip": null,
        "pdf": "https://pillow.readthedocs.io/_/downloads/en/stable/pdf/"
      },
      "hidden": false,
      "ref": "13.0.0",
      "slug": "stable",
      "type": "tag",
      "verbose_name": "stable"
    },
    {
      "documentation_url": "https://pillow.readthedocs.io/en/latest/",
      "downloads": {
        "epub": null,
        "htmlzip": null,
        "pdf": "https://pillow.readthedocs.io/_/downloads/en/latest/pdf/"
      },
      "hidden": false,
      "ref": null,
      "slug": "latest",
      "type": "branch",
      "verbose_name": "latest"
    }
  ]
}
```

### List pages

- Capability: `developer-documentation/list_pages`
- Description: Every page of one version of a Read the Docs project, from the generator's own search index: Sphinx searchindex.js (docnames and titles, with URLs built for the html or dirhtml builder from _static/documentation_options.js) or MkDocs search/search_index.json or Zensical search.json (entries without an anchor). Returns title, path and URL per page with optional path_prefix (a section such as user-guide/) and q filters and offset paging, so a section can be listed and then read page by page with get_page. Sites built with other generators are not_found.
- Instructions: To see what a project's docs contain, browse a version's table of pages, or find pages by title before reading them with get_page.
- Cost: 5 credits per call
- Capability file: [List pages](https://firecrawl.dev/alexandria/agents/providers/readthedocs-io/developer-documentation/list_pages)

Accepted options:
- `limit` (number): Pages to return (default 200). Example: `10`
- `offset` (number): Pages to skip; pass next_offset to continue. Example: `10`
- `path_prefix` (string): Only pages whose path starts with this, relative to the version root (user-guide/, operator-manual/) or from the site root (/en/stable/user-guide/). Example: `<path_prefix>`
- `project` (string): Read the Docs project slug, the <project> in https://<project>.readthedocs.io (e.g. pillow, argo-cd, pypdf, pymupdf). Pattern: ^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$. Example: `<project>`
- `q` (string): Case-insensitive substring filter on page title or path. Example: `<q>`
- `url` (string): Alternatively any page URL on https://<project>.readthedocs.io/; the project (and, where the function uses it, the version) is read from it. Exactly one of project or url. Pattern: ^[Hh][Tt][Tt][Pp][Ss]?://. Example: `<url>`
- `version` (string): Version slug as it appears in the docs URL (latest, stable, a branch or tag slug such as release-3.6 or 6.1.0). Defaults to the project's default version. Pattern: ^[A-Za-z0-9._-]{1,100}$. Example: `<version>`

Response schema example:
```json
{
  "count": 11,
  "generator": "mkdocs",
  "next_offset": null,
  "observed_at_ms": 1792696098409,
  "offset": 0,
  "pages": [
    {
      "path": "user-guide/auto_sync/",
      "title": "Automated Sync Policy",
      "url": "https://argo-cd.readthedocs.io/en/stable/user-guide/auto_sync/"
    },
    {
      "path": "user-guide/selective_sync/",
      "title": "Selective Sync",
      "url": "https://argo-cd.readthedocs.io/en/stable/user-guide/selective_sync/"
    },
    {
      "path": "user-guide/sync-kubectl/",
      "title": "Sync Applications with Kubectl",
      "url": "https://argo-cd.readthedocs.io/en/stable/user-guide/sync-kubectl/"
    },
    {
      "path": "user-guide/sync-options/",
      "title": "Sync Options",
      "url": "https://argo-cd.readthedocs.io/en/stable/user-guide/sync-options/"
    },
    {
      "path": "user-guide/sync-waves/",
      "title": "Sync Phases and Waves",
      "url": "https://argo-cd.readthedocs.io/en/stable/user-guide/sync-waves/"
    },
    {
      "path": "user-guide/sync_windows/",
      "title": "Sync Windows",
      "url": "https://argo-cd.readthedocs.io/en/stable/user-guide/sync_windows/"
    },
    {
      "path": "user-guide/commands/argocd_app_sync/",
      "title": "argocd app sync Command Reference",
      "url": "https://argo-cd.readthedocs.io/en/stable/user-guide/commands/argocd_app_sync/"
    },
    {
      "path": "user-guide/commands/argocd_proj_windows_disable-manual-sync/",
      "title": "argocd proj windows disable-manual-sync Command Reference",
      "url": "https://argo-cd.readthedocs.io/en/stable/user-guide/commands/argocd_proj_windows_disable-manual-sync/"
    },
    {
      "path": "user-guide/commands/argocd_proj_windows_disable-sync-overrun/",
      "title": "argocd proj windows disable-sync-overrun Command Reference",
      "url": "https://argo-cd.readthedocs.io/en/stable/user-guide/commands/argocd_proj_windows_disable-sync-overrun/"
    },
    {
      "path": "user-guide/commands/argocd_proj_windows_enable-manual-sync/",
      "title": "argocd proj windows enable-manual-sync Command Reference",
      "url": "https://argo-cd.readthedocs.io/en/stable/user-guide/commands/argocd_proj_windows_enable-manual-sync/"
    },
    {
      "path": "user-guide/commands/argocd_proj_windows_enable-sync-overrun/",
      "title": "argocd proj windows enable-sync-overrun Command Reference",
      "url": "https://argo-cd.readthedocs.io/en/stable/user-guide/commands/argocd_proj_windows_enable-sync-overrun/"
    }
  ],
  "path_prefix": "user-guide/",
  "project": "argo-cd",
  "root_url": "https://argo-cd.readthedocs.io/en/stable/",
  "total": 11,
  "version": "stable"
}
```

### Search docs

- Capability: `developer-documentation/search_docs`
- Description: Full-text search of one Read the Docs project with the platform's own search API (GET https://<project>.readthedocs.io/_/api/v3/search/?q=project:<project>/<version> <query>): ranked pages with title, URL, path, project and version, and the matching sections (anchor id, title, deep link, a 500-character content snippet and plain-text highlights). Searches the default version unless version is given; a pasted URL searches that URL's version. Paginates with page and next_page. An unknown project or version is not_found; a query with no hits is an empty result.
- Instructions: To find where a topic, API or setting is documented in a Read the Docs project (e.g. resize in pillow, sync waves in argo-cd), then read the hit with get_page.
- Cost: 5 credits per call
- Capability file: [Search docs](https://firecrawl.dev/alexandria/agents/providers/readthedocs-io/developer-documentation/search_docs)

Accepted options:
- `page` (number): Result page, 1-based; pass next_page to continue. Example: `10`
- `project` (string): Read the Docs project slug, the <project> in https://<project>.readthedocs.io (e.g. pillow, argo-cd, pypdf, pymupdf). Pattern: ^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$. Example: `<project>`
- `query` (string, required): Search terms (the platform's full-text syntax). Example: `<query>`
- `url` (string): Alternatively any page URL on https://<project>.readthedocs.io/; the project (and, where the function uses it, the version) is read from it. Exactly one of project or url. Pattern: ^[Hh][Tt][Tt][Pp][Ss]?://. Example: `<url>`
- `version` (string): Version slug as it appears in the docs URL (latest, stable, a branch or tag slug such as release-3.6 or 6.1.0). Defaults to the project's default version. Pattern: ^[A-Za-z0-9._-]{1,100}$. Example: `<version>`

Response schema example:
```json
{
  "count": 15,
  "filter": "project:pillow/stable",
  "next_page": 2,
  "observed_at_ms": 1792696070666,
  "page": 1,
  "project": "pillow",
  "query": "resize",
  "results": [
    {
      "path": "/en/stable/releasenotes/2.7.0.html",
      "project": "pillow",
      "sections": [
        {
          "content": "In most cases, convolution is more a expensive algorithm for downscaling because it takes into account all the pixels of source image. Therefore BILINEAR and BICUBIC filters’ performance can be lower than before. On the other hand the quality of BILINEAR and BICUBIC was close to NEAREST. So if such quality is suitable for your tasks you can switch to NEAREST filter for downscaling, which will give a huge improvement in performance. At the same time performance of convolution resampling for downs...",
          "highlights": [
            "Resize performance"
          ],
          "id": "resize-performance",
          "title": "Resize performance",
          "type": "section",
          "url": "https://pillow.readthedocs.io/en/stable/releasenotes/2.7.0.html#resize-performance"
        },
        {
          "content": "Image resizing methods resize() and thumbnail() take a resample argument, which tells which filter should be used for resampling. Possible values are: NEAREST, BILINEAR, BICUBIC and ANTIALIAS. Almost all of them were changed in this version.",
          "highlights": [
            "Image resizing methods resize() and thumbnail() take a resample argument, which tells which filter should"
          ],
          "id": "image-resizing-filters",
          "title": "Image resizing filters",
          "type": "section",
          "url": "https://pillow.readthedocs.io/en/stable/releasenotes/2.7.0.html#image-resizing-filters"
        },
        {
          "content": "A new LANCZOS constant was added instead of ANTIALIAS. When ANTIALIAS was initially added, it was the only high-quality filter based on convolutions. It’s name was supposed to reflect this. Starting from Pillow 2.7.0 all resize method are based on convolutions. All of them are antialias from now on. And the real name of the ANTIALIAS filter is Lanczos filter. The ANTIALIAS constant is left for backward compatibility and is an alias for LANCZOS.",
          "highlights": [
            "Starting from Pillow 2.7.0 all resize method are based on convolutions."
          ],
          "id": "antialias-renamed-to-lanczos",
          "title": "Antialias renamed to Lanczos",
          "type": "section",
          "url": "https://pillow.readthedocs.io/en/stable/releasenotes/2.7.0.html#antialias-renamed-to-lanczos"
        }
      ],
      "title": "2.7.0 (2014-12-31)",
      "title_highlights": [],
      "url": "https://pillow.readthedocs.io/en/stable/releasenotes/2.7.0.html",
      "version": "stable"
    },
    {
      "path": "/en/stable/reference/ImageOps.html",
      "project": "pillow",
      "sections": [
        {
          "content": "from PIL import Image, ImageOps size = (100, 150) with Image.open(\"Tests/images/hopper.webp\") as im: ImageOps.contain(im, size).save(\"imageops_contain.webp\") ImageOps.cover(im, size).save(\"imageops_cover.webp\") ImageOps.fit(im, size).save(\"imageops_fit.webp\") ImageOps.pad(im, size, color=\"#f00\").save(\"imageops_pad.webp\") # thumbnail() can also be used, # but will modify the image object in place im.thumbnail(size) im.save(\"image_thumbnail.webp\") thumbnail() contain() cover() fit() pad() Given si...",
          "highlights": [
            "Resize relative to a given size"
          ],
          "id": "resize-relative-to-a-given-size",
          "title": "Resize relative to a given size",
          "type": "section",
          "url": "https://pillow.readthedocs.io/en/stable/reference/ImageOps.html#resize-relative-to-a-given-size"
        },
        {
          "content": "Returns a resized version of the image, so that the requested size is covered, while maintaining the original aspect ratio. Parameters: image – The image to resize. size – The requested output size in pixels, given as a (width, height) tuple. method – Resampling method to use. Default is BICUBIC. See Filters. Returns: An image.",
          "highlights": [
            "Parameters: image – The image to resize. size – The requested output size in pixels, given as a (width"
          ],
          "id": "PIL.ImageOps.cover",
          "title": "PIL.ImageOps.cover(image: Image, size: tuple[int, int], method: int = Resampling.BICUBIC) → Image[source]",
          "type": "section",
          "url": "https://pillow.readthedocs.io/en/stable/reference/ImageOps.html#PIL.ImageOps.cover"
        },
        {
          "content": "Returns a resized version of the image, set to the maximum width and height within the requested size, while maintaining the original aspect ratio. Parameters: image – The image to resize. size – The requested output size in pixels, given as a (width, height) tuple. method – Resampling method to use. Default is BICUBIC. See Filters. Returns: An image.",
          "highlights": [
            "Parameters: image – The image to resize. size – The requested output size in pixels, given as a (width"
          ],
          "id": "PIL.ImageOps.contain",
          "title": "PIL.ImageOps.contain(image: Image, size: tuple[int, int], method: int = Resampling.BICUBIC) → Image[source]",
          "type": "section",
          "url": "https://pillow.readthedocs.io/en/stable/reference/ImageOps.html#PIL.ImageOps.contain"
        }
      ],
      "title": "ImageOps module",
      "title_highlights": [],
      "url": "https://pillow.readthedocs.io/en/stable/reference/ImageOps.html",
      "version": "stable"
    },
    {
      "path": "/en/stable/releasenotes/7.0.0.html",
      "project": "pillow",
      "sections": [
        {
          "content": "reduce() is a highly efficient operation to reduce an image by integer times. Normally, it shouldn’t be used directly. Used internally by resize() and thumbnail() methods to speed up resize when a new argument reducing_gap is set.",
          "highlights": [
            "Used internally by resize() and thumbnail() methods to speed up resize when a new argument reducing_gap"
          ],
          "id": "new-image-reduce-method",
          "title": "New Image.reduce() method",
          "type": "section",
          "url": "https://pillow.readthedocs.io/en/stable/releasenotes/7.0.0.html#new-image-reduce-method"
        },
        {
          "content": "The default resampling filter has been changed to the high-quality convolution Image.BICUBIC instead of Image.NEAREST, for the resize() method and the pad(), scale() and fit() functions. Image.NEAREST is still always used for images in “P” and “1” modes. See Filters to learn the difference. In short, Image.NEAREST is a very fast filter, but simple and low-quality.",
          "highlights": [
            "has been changed to the high-quality convolution Image.BICUBIC instead of Image.NEAREST, for the resize"
          ],
          "id": "default-resampling-filter",
          "title": "Default resampling filter",
          "type": "section",
          "url": "https://pillow.readthedocs.io/en/stable/releasenotes/7.0.0.html#default-resampling-filter"
        },
        {
          "content": "If the draft() method has no effect, it returns None. If it does have an effect, then it previously returned the image itself. However, unlike other chain methods, draft() does not return a modified version of the image, but modifies it in-place. So instead, if draft() has an effect, Pillow will now return a tuple of the image mode and a co-ordinate box. The box is the original coordinates in the bounds of resulting image. This may be useful in a subsequent resize() call.",
          "highlights": [
            "This may be useful in a subsequent resize() call."
          ],
          "id": "image-draft-return-value",
          "title": "Image.draft() return value",
          "type": "section",
          "url": "https://pillow.readthedocs.io/en/stable/releasenotes/7.0.0.html#image-draft-return-value"
        }
      ],
      "title": "7.0.0 (2020-01-02)",
      "title_highlights": [],
      "url": "https://pillow.readthedocs.io/en/stable/releasenotes/7.0.0.html",
      "version": "stable"
    },
    {
      "path": "/en/stable/handbook/concepts.html",
      "project": "pillow",
      "sections": [
        {
          "content": "For geometry operations that may map multiple input pixels to a single output pixel, the Python Imaging Library provides different resampling filters. Resampling.NEAREST Pick one nearest pixel from the input image. Ignore all other input pixels. Resampling.BOX Each pixel of the source image contributes to one pixel of the destination image with identical weights. For upscaling, this is equivalent to Resampling.NEAREST. This filter can only be used with the resize() and thumbnail() methods. Added...",
          "highlights": [
            "This filter can only be used with the resize() and thumbnail() methods. Added in version 3.4.0."
          ],
          "id": "filters",
          "title": "Filters",
          "type": "section",
          "url": "https://pillow.readthedocs.io/en/stable/handbook/concepts.html#filters"
        }
      ],
      "title": "Concepts",
      "title_highlights": [],
      "url": "https://pillow.readthedocs.io/en/stable/handbook/concepts.html",
      "version": "stable"
    },
    {
      "path": "/en/stable/releasenotes/13.0.0.html",
      "project": "pillow",
      "sections": [
        {
          "content": "Two new filters are available for resize() and thumbnail(): Image.Resampling.MKS2013 and Image.Resampling.MKS2021. These are versions of the Magic Kernel Sharp filter.",
          "highlights": [
            "Two new filters are available for resize() and thumbnail(): Image.Resampling.MKS2013 and Image.Resampling.MKS2021"
          ],
          "id": "new-resizing-filters",
          "title": "New resizing filters",
          "type": "section",
          "url": "https://pillow.readthedocs.io/en/stable/releasenotes/13.0.0.html#new-resizing-filters"
        },
        {
          "content": "The reducing_gap argument to resize() is now applied to RGBA and LA images. Previously, these modes ignored the argument, including when called by thumbnail(), which uses reducing_gap=2.0 by default.",
          "highlights": [
            "The reducing_gap argument to resize() is now applied to RGBA and LA images."
          ],
          "id": "resizing-images-with-alpha",
          "title": "Resizing images with alpha",
          "type": "section",
          "url": "https://pillow.readthedocs.io/en/stable/releasenotes/13.0.0.html#resizing-images-with-alpha"
        }
      ],
      "title": "13.0.0 (2026-10-16)",
      "title_highlights": [],
      "url": "https://pillow.readthedocs.io/en/stable/releasenotes/13.0.0.html",
      "version": "stable"
    },
    {
      "path": "/en/stable/releasenotes/4.0.0.html",
      "project": "pillow",
      "sections": [
        {
          "content": "The stretch function on the core image object has been removed. This used to be for enlarging the image, but has been aliased to resize recently.",
          "highlights": [
            "This used to be for enlarging the image, but has been aliased to resize recently."
          ],
          "id": "image-core-stretch-removed",
          "title": "Image.core.stretch removed",
          "type": "section",
          "url": "https://pillow.readthedocs.io/en/stable/releasenotes/4.0.0.html#image-core-stretch-removed"
        }
      ],
      "title": "4.0.0 (2017-01-01)",
      "title_highlights": [],
      "url": "https://pillow.readthedocs.io/en/stable/releasenotes/4.0.0.html",
      "version": "stable"
    },
    {
      "path": "/en/stable/handbook/tutorial.html",
      "project": "pillow",
      "sections": [
        {
          "content": "The PIL.Image.Image class contains methods to resize() and rotate() an image. The former takes a tuple giving the new size, the latter the angle in degrees counterclockwise.",
          "highlights": [
            "The PIL.Image.Image class contains methods to resize() and rotate() an image."
          ],
          "id": "geometrical-transforms",
          "title": "Geometrical transforms",
          "type": "section",
          "url": "https://pillow.readthedocs.io/en/stable/handbook/tutorial.html#geometrical-transforms"
        },
        {
          "content": "Instead of calculating the size of the new image when resizing, you can also choose to resize relative to a given size. from PIL import Image, ImageOps size = (100, 150) with Image.open(\"hopper.webp\") as im: ImageOps.contain(im, size).save(\"imageops_contain.webp\") ImageOps.cover(im, size).save(\"imageops_cover.webp\") ImageOps.fit(im, size).save(\"imageops_fit.webp\") ImageOps.pad(im, size, color=\"#f00\").save(\"imageops_pad.webp\") # thumbnail() can also be used, # but will modify the image object in...",
          "highlights": [
            "Instead of calculating the size of the new image when resizing, you can also choose to resize relative"
          ],
          "id": "relative-resizing",
          "title": "Relative resizing",
          "type": "section",
          "url": "https://pillow.readthedocs.io/en/stable/handbook/tutorial.html#relative-resizing"
        },
        {
          "content": "from PIL import Image, PSDraw import os # Define the PostScript file ps_file = open(\"hopper.ps\", \"wb\") # Create a PSDraw object ps = PSDraw.PSDraw(ps_file) # Start the document ps.begin_document() # Set the text to be drawn text = \"Hopper\" # Define the PostScript font font_name = \"Helvetica-Narrow-Bold\" font_size = 36 # Calculate text size (approximation as PSDraw doesn't provide direct method) # Assuming average character width as 0.6 of the font size text_width = len(text) * font_size * 0.6 te...",
          "highlights": [
            "image_path = \"hopper.ppm\" # Update this with your image path with Image.open(image_path) as im: # Resize"
          ],
          "id": "drawing-postscript",
          "title": "Drawing PostScript",
          "type": "section",
          "url": "https://pillow.readthedocs.io/en/stable/handbook/tutorial.html#drawing-postscript"
        }
      ],
      "title": "Tutorial",
      "title_highlights": [],
      "url": "https://pillow.readthedocs.io/en/stable/handbook/tutorial.html",
      "version": "stable"
    },
    {
      "path": "/en/stable/releasenotes/5.4.0.html",
      "project": "pillow",
      "sections": [
        {
          "content": "Now uses one resize operation with box parameter internally instead of a crop and scale operations sequence. This improves the performance and accuracy of cropping since the box parameter accepts float values.",
          "highlights": [
            "Now uses one resize operation with box parameter internally instead of a crop and scale operations sequence"
          ],
          "id": "imageops-fit",
          "title": "ImageOps.fit",
          "type": "section",
          "url": "https://pillow.readthedocs.io/en/stable/releasenotes/5.4.0.html#imageops-fit"
        }
      ],
      "title": "5.4.0 (2019-01-01)",
      "title_highlights": [],
      "url": "https://pillow.readthedocs.io/en/stable/releasenotes/5.4.0.html",
      "version": "stable"
    },
    {
      "path": "/en/stable/releasenotes/10.1.0.html",
      "project": "pillow",
      "sections": [
        {
          "content": "Returns a resized version of the image, so that the requested size is covered, while maintaining the original aspect ratio. See Resize relative to a given size for a comparison between this and similar ImageOps methods.",
          "highlights": [
            "See Resize relative to a given size for a comparison between this and similar ImageOps methods."
          ],
          "id": "imageops-cover",
          "title": "ImageOps.cover",
          "type": "section",
          "url": "https://pillow.readthedocs.io/en/stable/releasenotes/10.1.0.html#imageops-cover"
        }
      ],
      "title": "10.1.0 (2023-10-15)",
      "title_highlights": [],
      "url": "https://pillow.readthedocs.io/en/stable/releasenotes/10.1.0.html",
      "version": "stable"
    },
    {
      "path": "/en/stable/releasenotes/4.3.0.html",
      "project": "pillow",
      "sections": [
        {
          "content": "Added new argument box for PIL.Image.Image.resize(). This argument defines a source rectangle from within the source image to be resized. This is very similar to the image.crop(box).resize(size) sequence except that box can be specified with subpixel accuracy.",
          "highlights": [
            "This is very similar to the image.crop(box).resize(size) sequence except that box can be specified with"
          ],
          "id": "partial-resampling",
          "title": "Partial resampling",
          "type": "section",
          "url": "https://pillow.readthedocs.io/en/stable/releasenotes/4.3.0.html#partial-resampling"
        }
      ],
      "title": "4.3.0 (2017-10-02)",
      "title_highlights": [],
      "url": "https://pillow.readthedocs.io/en/stable/releasenotes/4.3.0.html",
      "version": "stable"
    },
    {
      "path": "/en/stable/handbook/image-file-formats.html",
      "project": "pillow",
      "sections": [
        {
          "content": "Pillow reads JPEG, JFIF, and Adobe JPEG files containing L, RGB, or CMYK data. It writes standard and progressive JFIF files. Using the draft() method, you can speed things up by converting RGB images to L, and resize images to 1/2, 1/4 or 1/8 of their original size while loading them. By default Pillow doesn’t allow loading of truncated JPEG files, set ImageFile.LOAD_TRUNCATED_IMAGES to override this.",
          "highlights": [
            "Using the draft() method, you can speed things up by converting RGB images to L, and resize images to"
          ],
          "id": "jpeg",
          "title": "JPEG",
          "type": "section",
          "url": "https://pillow.readthedocs.io/en/stable/handbook/image-file-formats.html#jpeg"
        }
      ],
      "title": "Image file formats",
      "title_highlights": [],
      "url": "https://pillow.readthedocs.io/en/stable/handbook/image-file-formats.html",
      "version": "stable"
    },
    {
      "path": "/en/stable/releasenotes/5.3.0.html",
      "project": "pillow",
      "sections": [
        {
          "content": "If you attempt to set the size of an image directly, e.g. im.size = (100, 100), you will now receive an AttributeError. This is not about removing existing functionality, but instead about raising an explicit error to prevent later consequences. The resize method is the correct way to change an image’s size. The exceptions to this are: The ICO and ICNS image formats, which use im.size = (100, 100) to select a subimage. The TIFF image format, which now has a DeprecationWarning for this action, as...",
          "highlights": [
            "The resize method is the correct way to change an image’s size."
          ],
          "id": "image-size",
          "title": "Image size",
          "type": "section",
          "url": "https://pillow.readthedocs.io/en/stable/releasenotes/5.3.0.html#image-size"
        }
      ],
      "title": "5.3.0 (2018-10-01)",
      "title_highlights": [],
      "url": "https://pillow.readthedocs.io/en/stable/releasenotes/5.3.0.html",
      "version": "stable"
    },
    {
      "path": "/en/stable/reference/ImageTransform.html",
      "project": "pillow",
      "sections": [
        {
          "content": "Bases: Transform Define a transform to extract a subregion from an image. Maps a rectangle (defined by two corners) from the image to a rectangle of the given size. The resulting image will contain data sampled from between the corners, such that (x0, y0) in the input image will end up at (0,0) in the output image, and (x1, y1) at size. This method can be used to crop, stretch, shrink, or mirror an arbitrary rectangle in the current image. It is slightly slower than crop, but about as fast as a...",
          "highlights": [
            "It is slightly slower than crop, but about as fast as a corresponding resize operation."
          ],
          "id": "PIL.ImageTransform.ExtentTransform",
          "title": "class PIL.ImageTransform.ExtentTransform(data: Sequence[Any])[source]",
          "type": "section",
          "url": "https://pillow.readthedocs.io/en/stable/reference/ImageTransform.html#PIL.ImageTransform.ExtentTransform"
        }
      ],
      "title": "ImageTransform module",
      "title_highlights": [],
      "url": "https://pillow.readthedocs.io/en/stable/reference/ImageTransform.html",
      "version": "stable"
    },
    {
      "path": "/en/stable/genindex.html",
      "project": "pillow",
      "sections": [
        {
          "content": "R10G10B10_XR_BIAS_A2_UNORM (PIL.DdsImagePlugin.DXGI_FORMAT attribute) R10G10B10A2_TYPELESS (PIL.DdsImagePlugin.DXGI_FORMAT attribute) R10G10B10A2_UINT (PIL.DdsImagePlugin.DXGI_FORMAT attribute) R10G10B10A2_UNORM (PIL.DdsImagePlugin.DXGI_FORMAT attribute) R11G11B10_FLOAT (PIL.DdsImagePlugin.DXGI_FORMAT attribute) R16_FLOAT (PIL.DdsImagePlugin.DXGI_FORMAT attribute) R16_SINT (PIL.DdsImagePlugin.DXGI_FORMAT attribute) R16_SNORM (PIL.DdsImagePlugin.DXGI_FORMAT attribute) R16_TYPELESS (PIL.DdsImagePl...",
          "highlights": [
            "attribute) reset() (PIL.ImageFile.Parser method) (PIL.TiffImagePlugin.ImageFileDirectory_v2 method) resize"
          ],
          "id": "R",
          "title": "R",
          "type": "section",
          "url": "https://pillow.readthedocs.io/en/stable/genindex.html#R"
        }
      ],
      "title": "Index",
      "title_highlights": [],
      "url": "https://pillow.readthedocs.io/en/stable/genindex.html",
      "version": "stable"
    },
    {
      "path": "/en/stable/_modules/PIL/ImageTransform.html",
      "project": "pillow",
      "sections": [
        {
          "content": "# # The Python Imaging Library. # $Id$ # # transform wrappers # # History: # 2002-04-08 fl Created # # Copyright (c) 2002 by Secret Labs AB # Copyright (c) 2002 by Fredrik Lundh # # See the README file for information on usage and redistribution. # from __future__ import annotations from . import Image TYPE_CHECKING = False if TYPE_CHECKING: from collections.abc import Sequence from typing import Any [docs] class Transform(Image.ImageTransformHandler): \"\"\"Base class for other transforms defined...",
          "highlights": [
            "It is slightly slower than crop, but about as fast as a corresponding resize operation."
          ],
          "id": "furo-main-content",
          "title": "Source code for PIL.ImageTransform",
          "type": "section",
          "url": "https://pillow.readthedocs.io/en/stable/_modules/PIL/ImageTransform.html#furo-main-content"
        }
      ],
      "title": "Source code for PIL.ImageTransform",
      "title_highlights": [],
      "url": "https://pillow.readthedocs.io/en/stable/_modules/PIL/ImageTransform.html",
      "version": "stable"
    }
  ],
  "total": 17,
  "version": "stable"
}
```
