---
title: "Adding annotations to a PDF document | Nutrient Python SDK"
canonical_url: "https://www.nutrient.io/guides/python/editor/add-annotations-to-pdf/"
md_url: "https://www.nutrient.io/guides/python/editor/add-annotations-to-pdf.md"
last_updated: "2026-06-09T10:32:42.848Z"
description: "How to add annotations to a PDF using Nutrient Python SDK."
---

# Adding annotations to a PDF document

Adding PDF annotations programmatically enables teams to automate document review workflows, build collaboration tools, and implement markup systems. Whether you’re building document approval systems, implementing automated feedback tools, or creating document annotation platforms, the annotations API provides complete control over annotation types, enabling you to add sticky notes, text markup, stamps, and links, and manage existing annotations without manual PDF editing.

[Download sample](https://www.nutrient.io/downloads/samples/python/add-annotations-to-pdf.zip)

## How Nutrient helps you achieve this

Nutrient Python SDK handles PDF annotation structures and appearance stream generation. With the SDK, you don’t need to worry about:

- Parsing annotation dictionaries and appearance streams

- Managing annotation flags and border styles

- Handling coordinate transformations and bounding box calculations

- Complex annotation state management and reply chains

Instead, Nutrient provides an API that handles all the complexity behind the scenes, letting you focus on your business logic.

## Complete implementation

Below is a complete working example that demonstrates adding various annotation types to a PDF. The following lines set up the Python application. The import statements bring in all necessary classes from the Nutrient SDK:

```python

from nutrient_sdk import Document
from nutrient_sdk import PdfEditor
from nutrient_sdk import Color
from nutrient_sdk import NutrientException

```

The `main()` function defines the entry point that will contain the annotation creation logic. The `Document.open()` call opens the PDF document. The [context manager](https://docs.python.org/3/reference/datamodel.html#context-managers) syntax ensures the document is automatically closed when you’re done, preventing resource leaks. The following code creates a PDF editor, accesses the page collection, and ensures at least one page exists by adding a letter-size page (612×792 points) if the document is empty:

```python

def main():
    try:
        with Document.open("input.pdf") as document:
            editor = PdfEditor.edit(document)
            pages = editor.page_collection

            if pages.count == 0:
                pages.add(612.0, 792.0)

            page = pages.first
            annotations = page.annotation_collection

```

`annotations` is bound to `page = pages.first`, so all annotations added through this collection are created on that first page.

The following code adds a sticky note annotation at coordinates (100, 700) with author metadata, subject, and comment text. After creation, the color is set to yellow using ARGB values (alpha, red, green, blue). Sticky notes are useful for adding comments and review feedback to documents:

```python

            sticky_note = annotations.add_sticky_note(
                100.0, 700.0,
                "Test Author",
                "Test Subject",
                "This is a sticky note comment"
            )
            # Customize the color

            sticky_note.color = Color.from_argb(255, 255, 255, 0)

```

The following code blocks add four text markup annotation types: highlight, underline, strikeout, and squiggly. Each annotation is positioned using x, y, width, and height coordinates to define the markup area. The methods accept author and contents parameters for metadata. Colors are customized after creation using ARGB values. These annotations are commonly used for document review workflows to mark text for emphasis, correction, or deletion:

```python

            highlight = annotations.add_highlight(
                50.0, 600.0, 150.0, 20.0,  # x, y, width, height

                "Highlighter",
                "Highlighted text area"
            )
            highlight.color = Color.from_argb(128, 255, 255, 0)

            underline = annotations.add_underline(
                50.0, 550.0, 150.0, 20.0,  # x, y, width, height

                "Underliner",
                "Underlined text area"
            )
            underline.color = Color.from_argb(255, 0, 0, 255)

            strike_out = annotations.add_strike_out(
                50.0, 500.0, 150.0, 20.0,  # x, y, width, height

                "Striker",
                "Struck out text area"
            )
            strike_out.color = Color.from_argb(255, 255, 0, 0)

            squiggly = annotations.add_squiggly(
                50.0, 450.0, 150.0, 20.0,  # x, y, width, height

                "Squiggler",
                "Squiggly underlined area"
            )
            squiggly.color = Color.from_argb(255, 0, 128, 0)

```

The following code adds a rubber stamp annotation at coordinates (300, 600) with dimensions 100×50 points. Stamps are created with a default “Draft” style and can be customized with title and contents text. The color is set to purple using ARGB values. Stamp annotations are typically used for approval workflows to indicate document status:

```python

            stamp = annotations.add_stamp(
                300.0, 600.0, 100.0, 50.0,  # x, y, width, height

                "Stamp Title",
                "Stamp contents"
            )
            # Customize the color

            stamp.color = Color.from_argb(255, 128, 0, 128)

```

The following code adds a new page to the document and creates an internal link annotation at coordinates (300, 500) with dimensions 200×20 points. The `set_destination()` method configures the link to navigate to page 2 at coordinates (0, 792). Note that `annotations` still points to the first page (`pages.first`), so this link annotation is created on the original first page, not on the newly added page. Link annotations enable navigation within documents and to external resources:

```python

            pages.add(612.0, 792.0)

            page_link = annotations.add_link(300.0, 500.0, 200.0, 20.0)
            page_link.set_destination(2, 0.0, 792.0)

```

The annotation collection supports iteration using a for loop, enabling you to examine or process all annotations on a page. The `type(annot).__name__` expression retrieves the annotation type for logging or filtering purposes. Iteration includes both pre-existing annotations and the ones added in this sample, so the printed list can contain more items or types than the newly created annotations alone. The `remove_at()` method removes the annotation at the specified zero-based index; `remove_at(0)` removes whichever annotation is currently first on that page, which may be an existing annotation if the input already contains annotations. The following code iterates through all annotations, prints their types, removes the first annotation, saves the changes, and closes the editor. The try-except block handles potential errors using `NutrientException`:

```python

            for annot in annotations:
                print(f"Annotation: {type(annot).__name__}")

            annotations.remove_at(0)

            editor.save_as("output.pdf")
            editor.close()
    except NutrientException as e:
        print(f"Error: {e}")

if __name__ == "__main__":
    main()

```

## Conclusion

The annotation creation workflow consists of several key operations:

1. Open the document and create an editor.

2. Access the page collection and ensure at least one page exists.

3. Retrieve the annotation collection for the target page.

4. Add sticky note annotations with author and comment metadata.

5. Add text markup annotations (highlight, underline, strikeout, squiggly) with positioning and colors.

6. Add stamp annotations for document status indication.

7. Add link annotations for internal page navigation.

8. Iterate through annotations for processing or filtering.

9. Remove annotations by index position.

10. Save and close the editor.

Nutrient handles annotation dictionary structures and appearance stream generation so you don’t need to understand PDF annotation specifications or manage coordinate transformations manually.
---

## Related pages

- [Adding a custom page to a PDF document](/guides/python/editor/add-custom-page-to-pdf.md)
- [Adding invisible digital signatures to a PDF document](/guides/python/editor/add-invisible-signature-to-pdf.md)
- [Adding interactive form fields to a PDF document](/guides/python/editor/add-form-fields-to-pdf.md)
- [Adding free text annotations to a PDF document](/guides/python/editor/add-freetext-annotations-to-pdf.md)
- [Adding link annotations to a PDF document](/guides/python/editor/add-link-annotations-to-pdf.md)
- [Adding redaction annotations to a PDF document](/guides/python/editor/add-redaction-annotations-to-pdf.md)
- [Adding shape annotations to a PDF document](/guides/python/editor/add-shape-annotations-to-pdf.md)
- [Adding stamp annotations to a PDF document](/guides/python/editor/add-stamp-annotations-to-pdf.md)
- [Adding sticky note annotations to a PDF document](/guides/python/editor/add-sticky-note-annotations-to-pdf.md)
- [Adding text markup annotations to a PDF document](/guides/python/editor/add-text-markup-annotations-to-pdf.md)
- [Advanced digital signature workflows](/guides/python/editor/advanced-digital-signatures.md)
- [Adding visible digital signatures to a PDF document](/guides/python/editor/add-visible-signature-to-pdf.md)
- [Detecting and adding form fields to a PDF document](/guides/python/editor/detect-and-add-form-fields.md)
- [Editing PDF form fields](/guides/python/editor/editing-pdf-form-fields.md)
- [Editing PDF metadata with Nutrient Python SDK](/guides/python/editor/editing-pdf-metadata.md)
- [Managing PDF page order](/guides/python/editor/manage-pdf-page-order.md)
- [Merging PDFs](/guides/python/editor/merge-pdf-into-other-pdf.md)
- [Nutrient Python SDK editor guides](/guides/python/editor.md)
- [Filling PDF form fields](/guides/python/editor/fill-pdf-form.md)

