Using Dynamic Data

Last updated March 23, 2026

When you generate a Document with PDFMonkey, you send data to use with the Template you selected. A Template’s test data are fake data that look like the ones you would use when generating a Document. Their purpose is to help you build the Template and test different scenarios.

It’s usually more efficient to play with test data than to build your Template and test it by generating actual Documents. You get a shorter feedback loop and don’t consume your monthly quota.

As a convenience, your test data is copied as Document payload when generating a Document via the Dashboard. Aside from that, it is never used when generating Documents through the API.

The preview is a real PDF

When building your Template, the preview you see on the right of the editor shows you a real PDF. This means that if it looks nice in the preview, it will look the same when generating a Document.

Defining test data

Define your test data in the Test data tab of the Template editor. This serves two functions:

  • It helps you define the structure you want to use for your data
  • It provides test data you can play with when building your Template

Data in PDFMonkey, be it test data for a Template or the payload of a Document, is expressed using the JSON syntax.

We’ll take the example of an e-commerce order. You could imagine something like this:

{
  "orderId": 1234,
  "orderStatus": "pending",
  "invoiceId": null,
  "client": {
    "civility": "Mr",
    "fullName": "Peter Parker",
    "isNewClient": true
  },
  "lineItems": [
    { "product": "Super strong silk",     "quantity": 100, "price": 123.45 },
    { "product": "Electronic components", "quantity": 12,  "price": 12.34 }
  ]
}

Let’s take a look at what we have.

We got some order-related data with orderId and orderStatus. They use different type of data, an integer and a string.

We then get an invoiceId that is null to indicate an empty value. Given our order is pending it does not have an invoice yet, legit.

Things start to get interesting when we get to client as it’s a nested structure (usually referred to as “object”) containing its own data. You’ll notice a new type of data for isNewClient which is a boolean, a value that can be true or false.

And finally we get lineItems that is a list (usually referred to as an “array”) of, surprise, line items represented by object with properties for product, quantity and price.

Do you need to nest your data?

You don’t have to use a nested structure if you don’t like or need it. Here the client details could be defined as clientCivility, clientFullName and clientIsNewClient

Using your test data in the Template

Once you have defined your test data, you call it within your Template using Liquid.

Given the data we defined above, our HTML could start with something like this:

<p>Order num. {{orderId}} is currently {{orderStatus}}.</p>
<p>Client: {{client.civility}} {{client.fullName}}.</p>

As you can see we can reference our data items directly and use a dot (.) to access nested elements. This code would generate the following HTML output:

<p>Order num. 1234 is currently pending.</p>
<p>Client: Mr Peter Parker</p>

In the following guides, we’ll learn how to display content according to some condition or how to go over our line items list and display it properly.

Naming your variables

Your payload keys should never contain any dot or space and should never be only a number.

{
  // Valid keys
  "someVariable": "Some value",            // {{someVariable}}
  "some_variable": "Some value",           // {{some_variable}}
  "some-variable": "Some value",           // {{some-variable}}
  "SomeVariable": "Some value",            // {{SomeVariable}}
  "somevariable": "Some value",            // {{somevariable}}
  "some": { "variable": "Some value" },    // {{some.variable}}
  "2words": "Hello world",                 // {{2words}}

  // Invalid keys
  "some.variable": "Some value",
  "some variable": "Some value",
  "(someVariable)": "Some value",
  "'someVariable'": "Some value",
  "{{someVariable}}": "Some value",
  "2": "Some value",
  "$someVariable": "Some value"
}

Here is how you would call the valid keys in a template:

{{someVariable}}
{{some_variable}}
{{some-variable}}
{{SomeVariable}}
{{somevariable}}
{{some}}
{{2words}}

Creating variables in templates

Variable tags create new Liquid variables. Here are the two most common tags, but you can learn more in the official documentation.

assign

Read the complete assign documentation.

Creates a new named variable.

{% assign foo = "bar" %}
{{foo}}
bar

capture

Read the complete capture documentation.

Captures the string inside of the opening and closing tags and assigns it to a variable. Variables created using capture are stored as strings.

{% assign favorite_food = "pizza" %}
{% assign age = 35 %}

{% capture about_me %}
I am {{age}} and my favorite food is {{favorite_food}}.
{% endcapture %}

{{about_me}}
I am 35 and my favourite food is pizza.

Frequently asked questions

How do I pass dynamic data to a PDFMonkey template?
Define your data as a JSON object and send it as the document payload via the API or an integration. In the template, access values using Liquid syntax: {{ variableName }} for top-level keys, {{ object.property }} for nested values, and {% for item in array %} for arrays.
What is test data in PDFMonkey?
Test data is a JSON object defined in the Test Data tab of the template editor. It simulates the payload you would send via the API, letting you preview the template in real time without consuming your monthly document quota.
Can I use nested JSON objects and arrays in PDFMonkey templates?
Yes. PDFMonkey supports deeply nested JSON. Access nested values with dot notation (e.g., {{ client.fullName }}) and iterate over arrays with {% for item in lineItems %}. You can nest objects inside arrays and vice versa.