Table of Contents

HTTP Requests (Microservice Pattern)

When CobaltPDF is deployed as a dedicated PDF rendering service (e.g. an Azure Function or ASP.NET Core minimal API), client applications need a way to describe what PDF to generate without installing the full CobaltPDF library — including Chromium — themselves.

The CobaltPDF.Requests companion NuGet package solves this cleanly:

[Web App / Client]                         [PDF Rendering Service]
CobaltPDF.Requests (~50 KB)   HTTP POST ─▶  CobaltPDF (full library)
- PdfRequest                                 - CobaltEngine
- PdfResponse                                - Chromium + Playwright
- No Chromium                                - ExecuteAsync maps request → fluent API

Installation

Client application (web app, mobile backend, other microservices):

dotnet add package CobaltPDF.Requests

Rendering service (Azure Function, ASP.NET Core app, worker):

dotnet add package CobaltPDF
# CobaltPDF.Requests is included automatically as a dependency

PdfRequest — Full JSON Schema

{
  "url":           "https://example.com/invoice/42",
  "html":          null,

  "landscape":     false,
  "paperFormat":   "A4",
  "grayscale":     false,
  "printBackground": true,
  "mediaType":     "screen",

  "margins": {
    "top":    "10mm",
    "bottom": "10mm",
    "left":   "15mm",
    "right":  "15mm"
  },

  "header": "<div style='font-size:10px;text-align:center;width:100%'>My Company</div>",
  "footer": "<div style='font-size:10px;text-align:center;width:100%'>Page <span class='pageNumber'></span> of <span class='totalPages'></span></div>",

  "watermark": {
    "html":       "<div style='font-size:80px;color:red'>DRAFT</div>",
    "rotation":   -45,
    "opacity":    0.2,
    "vertical":   "middle",
    "horizontal": "center"
  },

  "waitStrategy":  "networkIdle",
  "waitTimeoutMs": 30000,

  "userAgent":  "Mozilla/5.0 (compatible; MyReportBot/1.0)",
  "extraHeaders": {
    "Authorization":   "Bearer eyJhbGci...",
    "Accept-Language": "en-GB,en;q=0.9"
  },

  "customJs":   "document.querySelector('.no-print')?.remove();",
  "bypassCsp":  false,

  "cookies": [
    {
      "name":     "session",
      "value":    "abc123",
      "domain":   "example.com",
      "path":     "/",
      "secure":   true,
      "httpOnly": false
    }
  ],

  "localStorage":   { "theme": "dark" },
  "sessionStorage": { "userId": "42" },

  "lazyLoadPages":   3,
  "lazyLoadDelayMs": 200,

  "encryption": {
    "userPassword":    "open123",
    "ownerPassword":   null,
    "allowPrinting":   true,
    "allowCopying":    false,
    "allowModification": false
  },

  "metadata": {
    "title":    "Invoice #42",
    "author":   "Billing System",
    "subject":  "Monthly Invoice",
    "keywords": "invoice, billing, 2026",
    "creator":  "MyApp"
  }
}

PdfRequest Property Reference

Property Type Default Description
url string? URL to render. Mutually exclusive with html.
html string? Raw HTML to render. Mutually exclusive with url.
landscape bool false Landscape orientation.
paperFormat string "A4" Paper size: "A4", "A3", "Letter", "Legal", "Tabloid".
margins object null (1 cm) Page margins as CSS length strings (e.g. "10mm", "1cm").
grayscale bool false Render in grayscale.
printBackground bool true Include CSS background colours and images.
mediaType string "screen" CSS media type: "screen" or "print".
header string? HTML header template (all pages).
footer string? HTML footer template (all pages).
watermark object Watermark overlay on every page.
waitStrategy string "networkIdle" Render trigger (see table below).
waitTimeoutMs int 30000 Timeout for wait strategy in milliseconds.
userAgent string? Browser User-Agent string. null uses Chromium's default.
extraHeaders object {} HTTP headers sent with every request (navigation and sub-resources).
customJs string? JavaScript to execute before capture.
bypassCsp bool false Bypass page Content Security Policy.
cookies array [] Browser cookies to inject before navigation.
localStorage object {} localStorage key/value pairs.
sessionStorage object {} sessionStorage key/value pairs.
lazyLoadPages int? null Viewport-heights to scroll for lazy content.
lazyLoadDelayMs int 200 Delay between scroll steps (ms).
encryption object Password protection settings.
metadata object PDF document properties.

waitStrategy Values

Value Behaviour
"networkIdle" Wait until no network activity for 500 ms (default)
"signal" Wait for window.cobaltNotifyRender() from page JavaScript
"selector:#my-id" Wait until the CSS selector is visible
"js:window.ready===true" Poll a JavaScript expression until truthy
"delay:2000" Fixed delay in milliseconds

Client Examples

C# — HttpClient

using CobaltPdf.Requests;
using System.Net.Http.Json;

var request = new PdfRequest
{
    Url         = "https://myapp.com/invoice/42",
    PaperFormat = "A4",
    Header      = "<div style='font-size:10px;text-align:center;width:100%'>My Company</div>",
    Footer      = "<div style='font-size:10px;text-align:center;width:100%'>Page <span class='pageNumber'></span></div>",
    Metadata    = new() { Title = "Invoice #42", Author = "Billing System" },
    Cookies     = [new() { Name = "session", Value = "abc123", Domain = "myapp.com" }]
};

var httpResponse = await httpClient.PostAsJsonAsync("https://pdf-service/api/pdf", request);
httpResponse.EnsureSuccessStatusCode();

// Option A — receive raw PDF bytes directly
var pdfBytes = await httpResponse.Content.ReadAsByteArrayAsync();

// Option B — receive PdfResponse JSON (includes metadata)
var pdfResponse = await httpResponse.Content.ReadFromJsonAsync<PdfResponse>();
byte[] pdfBytes2 = pdfResponse!.ToBytes();

JavaScript / TypeScript fetch

const request = {
  url: "https://myapp.com/invoice/42",
  paperFormat: "A4",
  landscape: false,
  metadata: { title: "Invoice #42" }
};

const response = await fetch("https://pdf-service/api/pdf", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify(request)
});

const pdfBlob = await response.blob();
const url = URL.createObjectURL(pdfBlob);
window.open(url); // open in browser tab

Server Examples

Azure Function (Isolated Worker)

using CobaltPdf;
using CobaltPdf.Configuration;
using CobaltPdf.Requests;
using CobaltPdf.Extensions;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.Http;
using System.Net;

public class PdfFunction
{
    private readonly CobaltEngine _renderer;

    public PdfFunction(CobaltEngine renderer) => _renderer = renderer;

    [Function("GeneratePdf")]
    public async Task<HttpResponseData> Run(
        [HttpTrigger(AuthorizationLevel.Function, "post", Route = "pdf")]
        HttpRequestData req,
        CancellationToken cancellationToken)
    {
        var request = await req.ReadFromJsonAsync<PdfRequest>();

        if (request is null)
        {
            var bad = req.CreateResponse(HttpStatusCode.BadRequest);
            await bad.WriteStringAsync("Invalid request body.");
            return bad;
        }

        var pdf = await request.ExecuteAsync(_renderer, cancellationToken);

        // Option A — return raw PDF bytes
        var response = req.CreateResponse(HttpStatusCode.OK);
        response.Headers.Add("Content-Type", "application/pdf");
        response.Headers.Add("Content-Disposition", "attachment; filename=output.pdf");
        await response.Body.WriteAsync(pdf.BinaryData, cancellationToken);
        return response;
    }
}

Function startup (Program.cs):

using CobaltPdf;
using CobaltPdf.Configuration;
using CobaltPdf.Extensions;

var host = new HostBuilder()
    .ConfigureFunctionsWorkerDefaults()
    .ConfigureServices(services =>
    {
        services.AddCobaltPdf(o => CloudEnvironment.ConfigureForAzure(o));
    })
    .Build();

CobaltEngine.SetLicense(Environment.GetEnvironmentVariable("COBALTPDF_LICENSE")!);
await CobaltEngine.PreWarmAsync();
await host.RunAsync();

ASP.NET Core Minimal API

using CobaltPdf;
using CobaltPdf.Configuration;
using CobaltPdf.Extensions;
using CobaltPdf.Requests;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCobaltPdf(o => CloudEnvironment.ConfigureForDocker(o));

var app = builder.Build();

CobaltEngine.SetLicense(app.Configuration["CobaltPdf:LicenseKey"]!);
await CobaltEngine.PreWarmAsync();

// POST /api/pdf → returns raw PDF bytes
app.MapPost("/api/pdf", async (PdfRequest request, CobaltEngine renderer, CancellationToken ct) =>
{
    var pdf = await request.ExecuteAsync(renderer, ct);
    return Results.File(pdf.BinaryData, "application/pdf", "output.pdf");
});

// POST /api/pdf/json → returns PdfResponse JSON
app.MapPost("/api/pdf/json", async (PdfRequest request, CobaltEngine renderer, CancellationToken ct) =>
{
    var pdf = await request.ExecuteAsync(renderer, ct);
    return Results.Ok(PdfResponse.FromBytes(pdf.BinaryData));
});

app.Run();

Returning the PDF

Your endpoint can respond in two ways depending on what's convenient for the caller:

Raw bytes (application/pdf)

Best for browser downloads, mobile apps, and direct file saves.

return Results.File(pdf.BinaryData, "application/pdf", "output.pdf");

JSON (PdfResponse)

Best when the caller is another service that needs to process the PDF programmatically. The PDF binary is Base64-encoded inside the JSON.

return Results.Ok(PdfResponse.FromBytes(pdf.BinaryData));
{
  "data":       "<base64-encoded PDF>",
  "sizeBytes":  142857,
  "renderedAt": "2026-02-20T10:30:00Z"
}

The client decodes it with:

var pdfResponse = await httpResponse.Content.ReadFromJsonAsync<PdfResponse>();
byte[] bytes = pdfResponse!.ToBytes();

Security Considerations

  • Protect your PDF endpoint with authentication (AuthorizationLevel.Function for Azure Functions, API key middleware or JWT for ASP.NET Core).
  • Never expose the endpoint publicly without authentication — it renders arbitrary URLs.
  • Consider whitelisting allowed domains in your endpoint if you do not control all callers.
  • Store your license key in environment variables or Azure Key Vault, never in source code.