How to Add PDF Bookmarks and Outlines in C# Using IronPDF

How to Add PDF Bookmarks & Outlines in C# Using IronPDF

IronPDF enables you to add bookmarks (outlines) to PDF documents in C#, creating navigational aids similar to a Table of Contents. Add single or multi-layer bookmarks to enhance document usability and help users jump to key sections quickly. This feature works seamlessly across Windows, Linux, and macOS environments.

Quickstart: Adding Bookmarks to Your PDF in C#

Get started quickly with IronPDF by adding bookmarks to your PDF documents. This guide demonstrates how to load an existing PDF, add bookmarks for navigation, and save the updated document. Perfect for developers looking to enhance PDF functionality in their C# projects.

  1. Install IronPDF with NuGet Package Manager

    PM > Install-Package IronPdf
  2. Copy and run this code snippet.

    var pdf = new IronPdf.PdfDocument("example.pdf");
    pdf.Bookmarks.AddBookMarkAtEnd("Chapter 1", 1);
    pdf.SaveAs("bookmarked.pdf");
  3. Deploy to test on your live environment

    Start using IronPDF in your project today with a free trial

    arrow pointer

How Do I Work with PDF Bookmarks in C#?

In Adobe Acrobat Reader, outlines (also known as bookmarks) are displayed in the left sidebar, providing a convenient way to jump to key sections of the document. Bookmarks function as an interactive table of contents, allowing readers to navigate complex documents efficiently.

With IronPDF, you can import PDF documents and perform various operations on existing outlines, such as adding, reordering, editing properties, and deleting bookmarks. This gives you full control over the organization and structure of your PDF files, similar to how you can merge or split PDFs for document management.

TipsAll page indices follow zero-based indexing.

How Do I Add Single Layer Bookmarks?

Adding a bookmark in IronPDF is straightforward. Use the AddBookmarkAtEnd method, specifying the bookmark name and corresponding page index. This functionality integrates well with other PDF operations like adding headers and footers or setting custom margins to create professional documents. Below is an example:

:path=/static-assets/pdf/content-code-examples/how-to/bookmarks-single-layer-bookmark.cs
using IronPdf;

// Create a new PDF or edit an existing document.
PdfDocument pdf = PdfDocument.FromFile("existing.pdf");

// Add a bookmark
pdf.Bookmarks.AddBookMarkAtEnd("NameOfBookmark", 0);

// Add a sub-bookmark
pdf.Bookmarks.AddBookMarkAtEnd("NameOfSubBookmark", 1);

pdf.SaveAs("singleLayerBookmarks.pdf");
Imports IronPdf

' Create a new PDF or edit an existing document.
Private pdf As PdfDocument = PdfDocument.FromFile("existing.pdf")

' Add a bookmark
pdf.Bookmarks.AddBookMarkAtEnd("NameOfBookmark", 0)

' Add a sub-bookmark
pdf.Bookmarks.AddBookMarkAtEnd("NameOfSubBookmark", 1)

pdf.SaveAs("singleLayerBookmarks.pdf")
$vbLabelText   $csharpLabel

The AddBookMarkAtEnd method appends bookmarks to the end of the existing bookmark list. For more control over bookmark placement, use AddBookMarkAtStart to insert bookmarks at the beginning of the list. Each bookmark references a specific page index, enabling precise navigation within the document.

Single-layer Bookmarks Document

How Do I Create Multi-Layer Bookmark Hierarchies?

IronPDF allows you to add bookmarks in a tree structure, which is particularly useful for maintaining navigability in large PDF documents. This feature is valuable when dealing with extensive collections of examination papers, sales reports, or receipt records from various dates and locations in a single PDF document. Like how you might create PDF forms for data collection, structured bookmarks help organize complex information hierarchically.

The AddBookMarkAtEnd method returns a IPdfBookMark object, allowing you to add child bookmarks. For example, use Children.AddBookMarkAtStart("Date1", 0) or Children.AddBookMarkAtEnd("Date1", 0) to add child bookmarks to the "Examination" bookmark. This nested structure creates a hierarchical organization that mirrors your document's logical flow. The following code demonstrates this concept:

:path=/static-assets/pdf/content-code-examples/how-to/bookmarks-multi-layer-bookmark.cs
using IronPdf;

// Load existing PDF document
PdfDocument pdf = PdfDocument.FromFile("examinationPaper.pdf");

// Assign IPdfBookMark object to a variable
var mainBookmark = pdf.Bookmarks.AddBookMarkAtEnd("Examination", 0);

// Add bookmark for days
var date1Bookmark = mainBookmark.Children.AddBookMarkAtStart("Date1", 1);

// Add bookmark for type of test
var paperBookmark = date1Bookmark.Children.AddBookMarkAtStart("Paper", 1);
paperBookmark.Children.AddBookMarkAtEnd("PersonA", 3);
paperBookmark.Children.AddBookMarkAtEnd("PersonB", 4);

// Add bookmark for days
var date2Bookmark = mainBookmark.Children.AddBookMarkAtEnd("Date2", 5);

// Add bookmark for type of test
var computerBookmark = date2Bookmark.Children.AddBookMarkAtStart("Computer", 5);
computerBookmark.Children.AddBookMarkAtEnd("PersonC", 6);
computerBookmark.Children.AddBookMarkAtEnd("PersonD", 7);

pdf.SaveAs("multiLayerBookmarks.pdf");
Imports IronPdf

' Load existing PDF document
Private pdf As PdfDocument = PdfDocument.FromFile("examinationPaper.pdf")

' Assign IPdfBookMark object to a variable
Private mainBookmark = pdf.Bookmarks.AddBookMarkAtEnd("Examination", 0)

' Add bookmark for days
Private date1Bookmark = mainBookmark.Children.AddBookMarkAtStart("Date1", 1)

' Add bookmark for type of test
Private paperBookmark = date1Bookmark.Children.AddBookMarkAtStart("Paper", 1)
paperBookmark.Children.AddBookMarkAtEnd("PersonA", 3)
paperBookmark.Children.AddBookMarkAtEnd("PersonB", 4)

' Add bookmark for days
Dim date2Bookmark = mainBookmark.Children.AddBookMarkAtEnd("Date2", 5)

' Add bookmark for type of test
Dim computerBookmark = date2Bookmark.Children.AddBookMarkAtStart("Computer", 5)
computerBookmark.Children.AddBookMarkAtEnd("PersonC", 6)
computerBookmark.Children.AddBookMarkAtEnd("PersonD", 7)

pdf.SaveAs("multiLayerBookmarks.pdf")
$vbLabelText   $csharpLabel

This hierarchical approach is particularly valuable when working with complex documents that require detailed organization. The nested structure allows users to expand and collapse bookmark sections, making navigation intuitive even in documents with hundreds of pages.

Multi-layer Bookmarks Document

How Do I Auto-Generate Bookmarks from HTML Headings?

When rendering HTML to PDF, IronPDF can automatically build a hierarchical bookmark outline from the document's heading structure (h1-h6) or any custom CSS selectors. This removes the need to manually call AddBookMarkAtEnd for each section.

Enable the feature with the AutoBookmarksFromHeadings property on RenderingOptions before calling RenderHtmlAsPdf or RenderUrlAsPdf:

:path=/static-assets/pdf/content-code-examples/how-to/bookmarks-auto-from-headings.cs
using IronPdf;

var renderer = new ChromePdfRenderer();

// Master switch: auto-generate bookmarks from HTML headings (h1-h6) during rendering
renderer.RenderingOptions.AutoBookmarksFromHeadings = true;

var html = @"
<h1>Annual Report</h1>
<h2>Executive Summary</h2>
<p>Overview of the year.</p>
<h2>Financial Results</h2>
<h3>Revenue</h3>
<h3>Expenses</h3>
<h2>Outlook</h2>
<p>Looking forward.</p>";

var pdf = renderer.RenderHtmlAsPdf(html);

// pdf.Bookmarks is already populated with a hierarchical outline matching the heading structure
pdf.SaveAs("auto-bookmarked.pdf");
Imports IronPdf

Dim renderer As New ChromePdfRenderer()

' Master switch: auto-generate bookmarks from HTML headings (h1-h6) during rendering
renderer.RenderingOptions.AutoBookmarksFromHeadings = True

Dim html As String = "
<h1>Annual Report</h1>
<h2>Executive Summary</h2>
<p>Overview of the year.</p>
<h2>Financial Results</h2>
<h3>Revenue</h3>
<h3>Expenses</h3>
<h2>Outlook</h2>
<p>Looking forward.</p>"

Dim pdf = renderer.RenderHtmlAsPdf(html)

' pdf.Bookmarks is already populated with a hierarchical outline matching the heading structure
pdf.SaveAs("auto-bookmarked.pdf")
$vbLabelText   $csharpLabel

The following properties control which elements are bookmarked:

  • AutoBookmarksFromHeadings (bool, default false): Turn the feature on. When set to true, IronPDF builds a bookmark outline from your HTML headings automatically.
  • AutoBookmarkMinHeadingLevel (int, default 1): The highest-level heading to start from. Set to 1 to include h1 (the top of the document).
  • AutoBookmarkMaxHeadingLevel (int, default 6): The deepest heading level to include. Set to 3 to bookmark only h1, h2, and h3 — ignoring h4 through h6.
  • AutoBookmarkCssSelectors (string[], default null): Use custom CSS selectors instead of heading tags. For example: ".chapter-title" or "[data-bookmark]".

Customizing Heading Levels and CSS Selectors

To restrict bookmarks to top-level headings only:

renderer.RenderingOptions.AutoBookmarksFromHeadings = true;
renderer.RenderingOptions.AutoBookmarkMaxHeadingLevel = 3;
renderer.RenderingOptions.AutoBookmarksFromHeadings = true;
renderer.RenderingOptions.AutoBookmarkMaxHeadingLevel = 3;
renderer.RenderingOptions.AutoBookmarksFromHeadings = True
renderer.RenderingOptions.AutoBookmarkMaxHeadingLevel = 3
$vbLabelText   $csharpLabel

To bookmark custom elements instead of headings, supply CSS selectors:

renderer.RenderingOptions.AutoBookmarksFromHeadings = true;
renderer.RenderingOptions.AutoBookmarkCssSelectors = new[]
{
    "h1",
    ".chapter-title",
    "[data-bookmark]"
};
renderer.RenderingOptions.AutoBookmarksFromHeadings = true;
renderer.RenderingOptions.AutoBookmarkCssSelectors = new[]
{
    "h1",
    ".chapter-title",
    "[data-bookmark]"
};
renderer.RenderingOptions.AutoBookmarksFromHeadings = True
renderer.RenderingOptions.AutoBookmarkCssSelectors = New String() {
    "h1",
    ".chapter-title",
    "[data-bookmark]"
}
$vbLabelText   $csharpLabel

How Do I Query the Rendered Location of HTML Elements?

After rendering, IronPDF can report exactly which page and coordinates a given HTML element ended up on. This replaces the older workaround of rendering first, extracting text, and searching pages manually.

Set ElementQuerySelectors on RenderingOptions before rendering, then call GetElementLocations on the resulting PdfDocument:

:path=/static-assets/pdf/content-code-examples/how-to/bookmarks-element-locations.cs
using IronPdf;
using System;

var renderer = new ChromePdfRenderer();

// Configure which elements should be queryable after rendering
renderer.RenderingOptions.ElementQuerySelectors = new[] { "h1", ".kpi-card" };

var html = @"
<h1>Q4 Dashboard</h1>
<div class='kpi-card'>Revenue: $1.2M</div>
<div class='kpi-card'>Growth: 18%</div>
<h1>Q3 Comparison</h1>
<div class='kpi-card'>Previous: $1.0M</div>";

var pdf = renderer.RenderHtmlAsPdf(html);

// Retrieve the rendered page location of each matched element
foreach (var location in pdf.GetElementLocations())
{
    Console.WriteLine($"'{location.Text}' on page {location.PageIndex + 1} " +
                      $"at ({location.Rectangle.X}, {location.Rectangle.Y})");
}

pdf.SaveAs("dashboard.pdf");
Imports IronPdf
Imports System

Dim renderer = New ChromePdfRenderer()

' Configure which elements should be queryable after rendering
renderer.RenderingOptions.ElementQuerySelectors = New String() {"h1", ".kpi-card"}

Dim html = "
<h1>Q4 Dashboard</h1>
<div class='kpi-card'>Revenue: $1.2M</div>
<div class='kpi-card'>Growth: 18%</div>
<h1>Q3 Comparison</h1>
<div class='kpi-card'>Previous: $1.0M</div>"

Dim pdf = renderer.RenderHtmlAsPdf(html)

' Retrieve the rendered page location of each matched element
For Each location In pdf.GetElementLocations()
    Console.WriteLine($"'{location.Text}' on page {location.PageIndex + 1} " &
                      $"at ({location.Rectangle.X}, {location.Rectangle.Y})")
Next

pdf.SaveAs("dashboard.pdf")
$vbLabelText   $csharpLabel

GetElementLocations returns a List<RenderedElementLocation> containing one entry per matched element:

Property Type What it tells you
Text string The text inside the element.
PageIndex int Which page the element ended up on (starts at 0).
Rectangle IronSoftware.Drawing.Rectangle The element's position on the page, in PDF points (1/72 inch). Origin is bottom-left.
ElementIndex int The element's order in the original HTML (starts at 0).

TipsResults are cached on first call. If you modify the document's annotations after rendering and need fresh coordinates, call ResetElementLocationCache to force a re-scan on the next GetElementLocations call.

Combining Auto-Bookmarks with Element Location Tracking

Auto-bookmarks and element location queries can be combined in a single render. For example, generating an outline from h1/h2 headings while tracking the page location of .invoice-total elements:

:path=/static-assets/pdf/content-code-examples/how-to/bookmarks-auto-and-locations.cs
using IronPdf;
using System;

var renderer = new ChromePdfRenderer();

// Auto-generate bookmarks from top-level headings only
renderer.RenderingOptions.AutoBookmarksFromHeadings = true;
renderer.RenderingOptions.AutoBookmarkMaxHeadingLevel = 2;

// Also track the page location of invoice totals after rendering
renderer.RenderingOptions.ElementQuerySelectors = new[] { ".invoice-total" };

var html = @"
<h1>Invoice #2026-001</h1>
<h2>Line Items</h2>
<p>Services rendered for Q1.</p>
<p class='invoice-total'>Subtotal: $4,500.00</p>
<h1>Invoice #2026-002</h1>
<h2>Line Items</h2>
<p>Consulting hours for Q2.</p>
<p class='invoice-total'>Subtotal: $7,200.00</p>";

var pdf = renderer.RenderHtmlAsPdf(html);

// Bookmarks are populated automatically; locations can be queried after rendering
foreach (var location in pdf.GetElementLocations())
{
    Console.WriteLine($"{location.Text} appears on page {location.PageIndex + 1}");
}

pdf.SaveAs("invoices.pdf");
Imports IronPdf
Imports System

Dim renderer As New ChromePdfRenderer()

' Auto-generate bookmarks from top-level headings only
renderer.RenderingOptions.AutoBookmarksFromHeadings = True
renderer.RenderingOptions.AutoBookmarkMaxHeadingLevel = 2

' Also track the page location of invoice totals after rendering
renderer.RenderingOptions.ElementQuerySelectors = New String() {".invoice-total"}

Dim html As String = "
<h1>Invoice #2026-001</h1>
<h2>Line Items</h2>
<p>Services rendered for Q1.</p>
<p class='invoice-total'>Subtotal: $4,500.00</p>
<h1>Invoice #2026-002</h1>
<h2>Line Items</h2>
<p>Consulting hours for Q2.</p>
<p class='invoice-total'>Subtotal: $7,200.00</p>"

Dim pdf = renderer.RenderHtmlAsPdf(html)

' Bookmarks are populated automatically; locations can be queried after rendering
For Each location In pdf.GetElementLocations()
    Console.WriteLine($"{location.Text} appears on page {location.PageIndex + 1}")
Next

pdf.SaveAs("invoices.pdf")
$vbLabelText   $csharpLabel

How Can I Retrieve and Navigate Existing Bookmarks?

IronPDF makes it easy to retrieve and view bookmarks in a PDF document. Navigating through the bookmark tree is straightforward and provides seamless access to different sections. This functionality is essential when working with existing PDFs that need editing or when implementing features like searching and replacing text within bookmarked sections. Consider the multi-layer bookmarks document example above.

The "Examination" bookmark has a Children property that points to the "Date1" and "Date2" bookmarks. The "Date1" bookmark has a NextBookmark property that points to the "Date2" bookmark. Additionally, the "Date1" bookmark has a Children property containing the "Paper" bookmark. This interconnected structure allows for sophisticated navigation patterns and document organization.

To retrieve all bookmarks in the opened PDF document, use the GetAllBookmarks method. This provides a comprehensive list of all bookmarks, allowing you to analyze and utilize the bookmark structure:

:path=/static-assets/pdf/content-code-examples/how-to/bookmarks-retrieve-bookmark.cs
using IronPdf;

// Load existing PDF document
PdfDocument pdf = PdfDocument.FromFile("multiLayerBookmarks.pdf");

// Retrieve bookmarks list
var mainBookmark = pdf.Bookmarks.GetAllBookmarks();
Imports IronPdf

' Load existing PDF document
Private pdf As PdfDocument = PdfDocument.FromFile("multiLayerBookmarks.pdf")

' Retrieve bookmarks list
Private mainBookmark = pdf.Bookmarks.GetAllBookmarks()
$vbLabelText   $csharpLabel

Please noteMerging two PDF documents with identical bookmark names can disrupt the bookmark list.

WarningOnly bookmarks created from page indices are supported. Bookmarks from other PDF elements will have their page index value set to -1.

Learn how to create a Table of Contents when generating PDF from HTML in the following article: "Creating a Table of Contents with IronPDF."

Ready to see what else you can do? Check out our tutorial page here: Organize PDFs

Frequently Asked Questions

How do I add bookmarks to a PDF document in C#?

IronPDF makes it easy to add bookmarks to PDF documents in C#. You can use the AddBookmarkAtEnd method to add single-layer bookmarks by specifying the bookmark name and page index. For example: pdf.Bookmarks.AddBookMarkAtEnd("Chapter 1", 1). This creates navigational aids similar to a table of contents that help users jump to key sections quickly.

What's the difference between AddBookmarkAtEnd and AddBookmarkAtStart methods?

IronPDF provides two methods for bookmark placement. The AddBookMarkAtEnd method appends bookmarks to the end of the existing bookmark list, while AddBookMarkAtStart inserts bookmarks at the beginning of the list. Both methods reference specific page indices for precise navigation within the document.

Can I create hierarchical bookmark structures with multiple levels?

Yes, IronPDF allows you to create multi-layer bookmark hierarchies in a tree structure. This is particularly useful for organizing complex documents with nested sections, similar to how you would structure a detailed table of contents with chapters and sub-chapters.

Is bookmark functionality compatible across different operating systems?

IronPDF's bookmark feature works seamlessly across Windows, Linux, and macOS environments. You can add, edit, and manage PDF bookmarks regardless of your operating system, ensuring consistent functionality across different platforms.

What operations can I perform on existing PDF bookmarks?

With IronPDF, you can perform various operations on existing PDF outlines including adding new bookmarks, reordering them, editing bookmark properties, and deleting unwanted bookmarks. This gives you full control over the organization and structure of your PDF files.

How are bookmarks displayed when users open the PDF?

In Adobe Acrobat Reader and similar PDF viewers, bookmarks created with IronPDF appear as outlines in the left sidebar. They function as an interactive table of contents, allowing readers to navigate complex documents efficiently by clicking to jump to specific sections.

Curtis Chau
Technical Writer

Curtis Chau holds a Bachelor’s degree in Computer Science (Carleton University) and specializes in front-end development with expertise in Node.js, TypeScript, JavaScript, and React. Passionate about crafting intuitive and aesthetically pleasing user interfaces, Curtis enjoys working with modern frameworks and creating well-structured, visually appealing manuals.

...

Read More
Ready to Get Started?
Nuget Downloads 19,404,524 | Version: 2026.6 just released
Still Scrolling Icon

Still Scrolling?

Want proof fast? PM > Install-Package IronPdf
run a sample watch your HTML become a PDF.