This is the full developer documentation for Oicana # Generate PDFs in your own infrastructure >

Print-ready PDFs created inside your app in milliseconds: Node, Python, Java, C#, Rust, PHP, or the browser. One template format. No headless Chrome, no per-document fees, no data leaving your servers.

Invoices, reports, contracts, certificates, and statements designed in Typst. Free for non-commercial use, commercial evaluation free for 30 days.

Templatemain.typ ```typst #import "@preview/oicana:0.2.0": setup #import "certificate.typ": * #let project-file(path) = read(path, encoding: none) #let (input, _, _) = setup(project-file) #let name = input.certificate.name #show: certificate.with(name: name) ``` Compile from BrowserNode.jsPythonJavaC#RustPHP ```ts import { Template } from "@oicana/browser"; const template = new Template(templateBytes); const inputs = new Map(); inputs.set("certificate", JSON.stringify({ name: "Alex Kim" })); const pdf = template.compile(inputs, new Map()); ``` ```ts import { Template } from "@oicana/node"; const template = new Template(templateBytes); const inputs = new Map(); inputs.set("certificate", JSON.stringify({ name: "Marcus Lee" })); const pdf = template.compile(inputs, new Map()); ``` ```python from oicana import Template import json template = Template(template_bytes) pdf = template.compile( json_inputs={"certificate": json.dumps({"name": "Priya Patel"})} ) ``` ```java import com.oicana.Template; Template template = new Template(templateBytes); byte[] pdf = template.compile( Map.of("certificate", "{\"name\": \"Jakob Müller\"}"), Map.of() ); ``` ```cs using Oicana; using System.Text.Json.Nodes; var template = new Template(templateBytes); var inputs = new Dictionary { ["certificate"] = JsonNode.Parse("{ \"name\": \"Sofía García\" }")! }; var pdf = template.Compile(inputs, new(), ExportFormat.Pdf(), new CompilationOptions(CompilationMode.Production)); ``` ```rust use oicana::Template; use oicana_input::{TemplateInputs, input::json::JsonInput}; let mut template = Template::init(Cursor::new(template_bytes))?; let mut inputs = TemplateInputs::new(); inputs.with_input(JsonInput::new( "certificate".into(), json!({ "name": "Yui Tanaka" }).to_string(), )); let pdf = template.compile(inputs)?; ``` ```php use Oicana\Template; $template = new Template($templateBytes); $pdf = $template->compile( jsonInputs: ['certificate' => ['name' => 'Anya Volkov']] ); ``` Outputcertificate.pdf ![Certificate for Alex Kim](/_astro/browser.ezxmiCIB.svg)![Certificate for Marcus Lee](/_astro/node.DP5XD3pw.svg)![Certificate for Priya Patel](/_astro/python.C75LnsLR.svg)![Certificate for Jakob Müller](/_astro/java.DMVjOi6Y.svg)![Certificate for Sofía García](/_astro/csharp.pmMnLrR3.svg)![Certificate for Yui Tanaka](/_astro/rust.C_dmNaX3.svg)![Certificate for Anya Volkov](/_astro/php.BuX6f-pz.svg) Your Data Stays With You PDFs are generated inside your own application. No data is sent to a third-party service, which keeps compliance with regulations like GDPR or HIPAA in your hands. That makes Oicana a fit for fintech, health, and other regulated software. With the browser integration, documents can even be created directly on your users’ devices. Flat Price, Unlimited Documents No metering, no per-document fees. One [flat license per application](#pricing) covers unlimited documents, seats, and environments. A hundred invoices a month cost the same as a hundred thousand. Non-commercial use is free. Milliseconds, Not Seconds No headless browser eating hundreds of megabytes of memory, no network round-trip. Warmed up templates produce non-trivial PDF files in single digit milliseconds, in process. Powerful Layouting Builds on the [modern open source typesetter Typst](https://typst.app/). Oicana templates can use all of Typst’s functionality including its [extensive package ecosystem](https://typst.app/universe/). Multi-platform The same templates can be compiled from the browser or server-side with C#, Java, Node.js, Rust, Python, and PHP. Templates Are Code Templates are plain text files. Diff them in Git, review them in pull requests, and let AI assist in writing them. Escape Vendor Lock-in Reuse templates with other Typst based solutions; The Typst compiler is open source! ## Documentation [Read the docs](/docs/)Oicana's documentation contains a getting started guide. [Your tech stack](/pdf-generation/)See an example for your stack: Node.js, Python, Java, C#, Rust, PHP, or the browser. [Examples](https://github.com/oicana/?q=example)Every Oicana integration has an open source example project in our GitHub organization. There you can also find a repository with example templates. [Guides](/docs/guides/)The documentation includes guides for common scenarios when using Oicana. [Comparisons](/compare/)How Oicana compares to Gotenberg, DocRaptor, PDFMonkey, Carbone, and other approaches. ## Pricing #### Non-commercial Free Oicana is source-available under the [PolyForm Noncommercial License 1.0.0](https://polyformproject.org/licenses/noncommercial/1.0.0). Any non-commercial use is free — personal projects, hobby use, research, and education. The license also explicitly permits use by charitable organizations, educational institutions, public research organizations, and government institutions, regardless of their funding source. [View license →](https://github.com/oicana/oicana/blob/main/LICENSE.md) #### Commercial Free 30-day trial Flat fee, no metering. Licenses are** per application**, priced by company size. Pay once for unlimited seats, environments, and documents. Every subscription includes all Oicana components like the CLI and the integrations. MonthlyAnnual Save 15% ### Startup For small companies and individuals Up to €2M yearly revenue 19.00€/ month Buy subscription ### Scaleup For growing companies Up to €25M yearly revenue 49.00€/ month Buy subscription ### Enterprise For large organizations Above €25M yearly revenue 199.00€/ month Buy subscription Free 30-day commercial evaluation. Every purchase is covered by a 30-day money-back guarantee. Oicana is in public beta and has been used in production since the alpha. Already subscribed?[Manage your subscriptions.](https://creem.io/my-orders/login) Our order processes are conducted by our merchant of record Creem. #### FAQ What counts as one application? An application is one distinct software product or internal tool, regardless of how many services, environments, or users it has. See [Section 4.3 of our Terms of Service](/terms-of-service/#43-per-application-licensing) for the binding definition. * A SaaS with multiple microservices generating documents1 application * Web, iOS, and Android apps sharing one backend1 application * Production, staging, and dev environments1 application * A customer-facing SaaS plus a separate internal admin tool2 applications * One codebase white-labeled and sold as 3 separate products (reach out to us for a custom solution)3 applications Can I try Oicana commercially before buying? Yes, commercial evaluation is free for 30 days from your first commercial use. You can follow the getting-started guide, build a proof-of-concept integration, and test and use Oicana in production without a subscription. See [Section 4.2 of our Terms of Service](/terms-of-service/#42-evaluation-use) for the full terms. Is Oicana open source? Oicana is source available, not open source. All code is public on [GitHub](https://github.com/oicana/oicana) under the [PolyForm Noncommercial License 1.0.0](https://polyformproject.org/licenses/noncommercial/1.0.0): non-commercial use is free, commercial use requires a subscription. The Typst package is MIT licensed, and the example projects and templates are open source under their respective licenses. Your templates are plain Typst projects and the Typst compiler itself is open source. Even if you stop using Oicana, most of your templates keep working with other Typst based tooling. Do you offer a money-back guarantee? Yes, we offer a 30-day money-back guarantee. If Oicana isn't the right fit, just email within 30 days of your purchase and we'll refund you in full. See our [Refund Policy](/refund-policy/) for the full terms. × ### Thank you for your purchase! Ready to dive in? Head to the [getting started guide](/docs/getting-started/1-setup/) to set up Oicana in your project. A confirmation email from Creem with your receipt should arrive in your inbox shortly. Not happy? You're covered by our **30-day money-back guarantee**, just contact us at . You can manage your subscription anytime through the [Creem customer portal](https://creem.io/my-orders/login). # Installation and Setup > Install the Oicana CLI and set up an editor for template development with Typst. No license needed to follow this guide For commercial use, the first 30 days are free for evaluation. Follow this guide, build a proof of concept, and test Oicana without a subscription. See [Section 4.2 of our Terms of Service](/terms-of-service/#42-evaluation-use) for the full terms. Non-commercial use of Oicana like personal projects, hobby use, research, education, and use by charitable, educational, public research, and government institutions is free under the [PolyForm Noncommercial License](https://polyformproject.org/licenses/noncommercial/1.0.0). To get started, you need the Oicana CLI and an editor for Typst. Both are only necessary on machines used for Oicana template development. An end-user machine, running software that uses an Oicana integration, does not require any additional installations. ## Oicana CLI [Section titled “Oicana CLI”](#oicana-cli) Install a [prebuild binary from GitHub](https://github.com/oicana/oicana/releases/tag/oicana_cli-v0.6.0) or let a script do that for you. Bash script: Shell script to install Oicana CLI ```bash curl --proto '=https' --tlsv1.2 -LsSf https://github.com/oicana/oicana/releases/download/oicana_cli-v0.6.0/oicana_cli-installer.sh | sh ``` Powershell script: Powershell script to install Oicana CLI ```powershell -ExecutionPolicy Bypass -c "irm https://github.com/oicana/oicana/releases/download/oicana_cli-v0.6.0/oicana_cli-installer.ps1 | iex" ``` After the installation, run `oicana --version` to make sure the installation succeeded. The CLI can manage Oicana templates. The most relevant commands for this guide are `oicana pack` to package a template and `oicana compile` if you want to test template compilation. See the [CLI chapter](/docs/cli/) for more information. ## Editor for Typst [Section titled “Editor for Typst”](#editor-for-typst) You can edit Typst files in any text editor, but syntax highlighting and live previews make development significantly easier. Here are some suggestions: * Several IDEs have Typst plugins with live previews and syntax highlighting. * Visual Studio Code: [Tinymist](https://marketplace.visualstudio.com/items?itemName=myriad-dreamin.tinymist) offers a complete experience with live preview, syntax/error highlighting and more. * JetBrains IDEs: [Kvasir](https://plugins.jetbrains.com/plugin/25061-kvasir) * [Official Typst editor in the browser](https://typst.app/). * This editor has a [significant free tier and a pro tier for $8 per month](https://typst.app/pricing/). It is maintained by the Typst company. * Web based; No installation required. * You can work on the same document with multiple people and sync your templates to GitHub or GitLab. ## For this Guide [Section titled “For this Guide”](#for-this-guide) In the following chapters, you will create a basic Oicana template that can be used with any integration. After creating the template, you’ll be able to choose which integration to explore based on your preferred tech stack. # Create a Template > Create your first Oicana template with static content and package it. The simplest Oicana template consists of a `typst.toml` file and a Typst source file with some static content. The `oicana new` command scaffolds both for you in one step. ## Template with static content [Section titled “Template with static content”](#template-with-static-content) We will use the `new` command of the Oicana CLI to create a starter template. If you are using the online Typst editor, manually create the files and paste their content. ```bash oicana new example ``` This creates an `example/` directory with two files. Open it in your IDE with Typst support. main.typ ```typst #set document(date: datetime.today()) = Hello Edit `main.typ` to design your template. ``` Note This Typst document uses [markup mode](https://typst.app/docs/reference/syntax/#markup), where `=` starts a heading, and plain text is just text. `#` switches to code mode, where you can call functions like `#set document(title: "Invoice")` or `#text(fill: blue)[...]` to style content. Refer to [Typst’s online documentation](https://typst.app/docs/) for the full reference. The preview of `main.typ` should show the heading and text. Note In an IDE, you might need to open the preview. For example, if you use VS Code with `Tinymist`, press `Ctrl` + `K` followed by `V` while the `main.typ` file is open. The companion `example/typst.toml` is the template manifest: typst.toml ```toml [package] name = "example" version = "0.1.0" entrypoint = "main.typ" [tool.oicana] manifest_version = 1 ``` It gives our template the name `example`, the semantic version `0.1.0`, and defines the entrypoint as `main.typ`. The `tool.oicana` section only configures the Oicana manifest version for now. To check that the manifest is well-formed, run `oicana validate` in the template directory. It will report any issues with `typst.toml` before you try to package or compile the template. ## Packaging [Section titled “Packaging”](#packaging) To compile the template through Oicana integrations, like shown in later chapters of this guide, it has to be packaged. Navigate into the template directory in a terminal and execute `oicana pack`. This will create a file called `example-0.1.0.zip`. Complete code at the end of this chapter main.typ ```typst #set document(date: datetime.today()) = Hello Edit `main.typ` to design your template. ``` typst.toml ```toml [package] name = "example" version = "0.1.0" entrypoint = "main.typ" [tool.oicana] manifest_version = 1 ``` # Defining Inputs > Learn how to define JSON and blob inputs for your Oicana template. There are two types of inputs. A `json` input contains structured data while a `blob` input passes bytes and optionally metadata to the template. For example, in an invoice the items and customer data could be a `json` input and the company logo could be a `blob` input. ## The Oicana Typst package [Section titled “The Oicana Typst package”](#the-oicana-typst-package) Template inputs are configured in the manifest file `typst.toml`. The Oicana Typst package determines the current values of inputs. Add the following to the top of your `main.typ` file to initialize the package: Beginning of main.typ ```typst #import "@preview/oicana:0.2.0": setup #let read-project-file(path) = read(path, encoding: none) #let (input, oicana-image, oicana-config) = setup(read-project-file) #set document(date: datetime.today()) ``` The `setup` method reads the manifest file and resolves all inputs. It returns three values: 1. *input* - dictionary of resolved input values, keyed by input key 2. *oicana-image* - a utility method, that takes the key of a blob input and returns the input as an image 3. *oicana-config* - dictionary with compilation metadata We only need the inputs for now. You can take a look at [the example templates](https://github.com/oicana/oicana-example-templates) to see the `oicana-image` helper in action. Why the \`read-project-file\` wrapper? The `setup` call needs access to the files in the template project. Due to how Typst handles paths, this currently requires passing a `read` closure from the template itself, as done with `read-project-file`. ## Defining inputs [Section titled “Defining inputs”](#defining-inputs) We will use a `json` input to pass a name into the template. Add the following to the end of the `typst.toml` file: typst.toml ```toml [[tool.oicana.inputs]] type = "json" key = "info" ``` The value of this input is now available in the template as `input.info`, where `info` is the key of the input as defined in `typst.toml`. While we develop the template, the value of the input will be `none`, because there is no Oicana integration setting a value for it. We can change that by defining a `default` or `development` value for the input. ### Default and Development values [Section titled “Default and Development values”](#default-and-development-values) Inputs can define two different fallback values, `default` and `development`. These fallback values differ in priority based on which mode the template is compiled in. When compiling a template in development mode, input values have the priority 1. Explicit input value (for example through an integration) 2. `development` value 3. `default` value If you compile in production mode, the `development` value is ignored: 1. Explicit input value (for example through an integration) 2. `default` value When to use each mode **Development mode** is used in two scenarios: * When developing templates in a Typst editor, live previews will use the development mode. The same goes for other tooling without Oicana integration (like the official Typst CLI). * By default, template registration (typically at application startup) uses development mode when warming up the Typst cache for the template to speed up later compilations. **Production mode** is the default for document compilation in integrations. It ensures the compilation fails explicitly rather than accidentally using test data for the document. If an input value is missing in production mode and the input does not have a `default` value, the compilation will fail unless you marked the input as not required and your template handles `none` values for it. While developing an Oicana template in a Typst editor, it will be compiled in development mode. It makes sense to define `development` values for all required inputs of your template to have a functioning preview. Let’s extend our input with a `development` value. First create an `info.json` file in the template directory: info.json ```json { "name": "Chuck Norris" } ``` Then extend the input definition and set the `development` value to be `info.json`: typst.toml ```toml [[tool.oicana.inputs]] type = "json" key = "info" development = "info.json" ``` In our template we can now use `input.info.name` and the preview will show “Chuck Norris”. Update your template to the following: main.typ ```typst #import "@preview/oicana:0.2.0": setup #let read-project-file(path) = read(path, encoding: none) #let (input, oicana-image, oicana-config) = setup(read-project-file) #set document(date: datetime.today()) = Hello from Typst, #input.info.name Now we can pass names into the template from any Oicana integration. ``` ## Compiling with the CLI [Section titled “Compiling with the CLI”](#compiling-with-the-cli) After changing the manifest, run `oicana validate` to confirm the new input definition is valid. If the JSON input has a schema, `validate` also checks that the `development` and `default` values match it. Running `oicana compile --development` should create a PDF file in an `output` directory. To set the input value from the CLI, copy `info.json` to `test-input.json` and change the name in the new file. Then run `oicana compile -j info=test-input.json` and the new PDF file in `output` will contain whatever name you configured. With the input defined in your template, you’re ready to choose an integration and learn how to pass dynamic values from your application code. In preparation for that, you should pack the template again using `oicana pack` to have the latest state of the template at hand. Complete code at the end of this chapter main.typ ```typst #import "@preview/oicana:0.2.0": setup #let read-project-file(path) = read(path, encoding: none) #let (input, oicana-image, oicana-config) = setup(read-project-file) #set document(date: datetime.today()) = Hello from Typst, #input.info.name Now we can pass names into the template from any Oicana integration. ``` typst.toml ```toml [package] name = "example" version = "0.1.0" entrypoint = "main.typ" [tool.oicana] manifest_version = 1 [[tool.oicana.inputs]] type = "json" key = "info" development = "info.json" ``` info.json ```json { "name": "Chuck Norris" } ``` # Browser / React > Integrate Oicana into a React application using WebAssembly. In this chapter, you’ll integrate Oicana into a React application using WebAssembly. Unlike the server-side integrations, Oicana runs entirely in the browser here - no server required for PDF generation. Note This chapter assumes that you have a working Node.js 18+ setup with npm. If that is not the case, please follow [the official Node.js installation guide](https://nodejs.org/en/download/) to install Node.js on your machine. It also assumes you have the packed template `example-0.1.0.zip` from the previous chapters. If you don’t, run `oicana pack` in your template directory first. Let’s start with a fresh React project using Vite. Run the following command: ```bash npm create vite@latest my-pdf-app -- --template react-ts cd my-pdf-app npm install ``` You can test it by running `npm run dev` and navigating to in your browser. ## Adding Oicana [Section titled “Adding Oicana”](#adding-oicana) Install the Oicana browser packages: ```bash npm install @oicana/browser @oicana/browser-wasm ``` Note The WASM file included in `@oicana/browser-wasm` is about 40 MB uncompressed (\~17 MB gzipped, \~12 MB brotli). It’s fetched once and browser-cached. For more about handling the WASM file read the [Deploying the Browser WASM](/docs/guides/browser-deployment/) guide. It covers pre-compression, CDN caveats, Web Worker offload, and a few other things that are easy to get wrong. 1. Create a `public` directory (if it doesn’t exist) and copy `example-0.1.0.zip` into it. This makes the template accessible to the browser. 2. Replace the contents of `src/App.tsx` with the following: src/App.tsx ```tsx import { useEffect, useState } from 'react'; import { initialize, Template, CompilationMode, Pdf } from '@oicana/browser'; import wasmUrl from '@oicana/browser-wasm/oicana_browser_wasm_bg.wasm?url'; function App() { const [template, setTemplate] = useState