> For the complete documentation index, see [llms.txt](https://help.docupilot.app/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://help.docupilot.app/document-template/excel-file-xlsx.md).

# Excel (XLSX)

## Getting Started

You can use Excel Spread Sheets ( .xlsx is the supported format ) as your document template, you can build your document in Ms Excel, Google Sheets or other supporting platforms and then upload it to Docupilot as a .xlsx file. Replace the info in excel sheet like client name, client company name to {{client.name}} and {{client.company}}.

![Excel Spread Sheet (.xlsx) template overview.](/files/-MWTNTe3hldvklresAqm)

### Uploading XLSX

![](/files/LePnwffP5gC3wSu22u8v)

### Updating XLSX

If you want to make changes to your Excel Spread Sheet make changes in MS Excel, Google Sheets etc , and upload it to Docupilot as a .xlsx file.

![](/files/ywOFBVmYDTDilO0OG3J4)

## Types of Merge Fields <a href="#types-of-merge-fields" id="types-of-merge-fields"></a>

Docupilot supports a variety of merge fields for you to use.

* Tokens (Merge Field)
* Condition (`if-else`)
* Iterating inside a cell
* Tables

### Tokens (Merge Field) <a href="#tokens-merge-field" id="tokens-merge-field"></a>

These are simple fields embraced in `{{}}`. When you provide your custom data, **Docupilot** will replace these fields with the data. For example **{{email}}, {{clientname}}, {{company\_name}}**.

If you want to group your fields you can use dot(.) while defining the tokens. For example your client has first name & last name, you can write the tokens as **{{client.first\_name}}, {{client.last\_name}}.**

### Condition (`if-else`)

You can use conditional statements to show or hide contents based on your data. For example, If you are creating an invoice, you want to display CASH if the payment\_mode is cash, else if the payment\_mode is the card you want to show CARD.

```
{{#if (payment_mode == "cash")}}
CASH
{{else if (payment_mode == "card")}}
CARD
{{else}}
Please Insert preferred Mode of Payment{{/if}}
```

To use conditional statement for checking inverse or negation of a condition, use the **not** in the condition. For example, to add an instruction requesting to add secure link if payment mode is not available on record:

```
{{#if (not payment_mode)}}
Please Add your payment details in this secure link: <your secure payment link>
{{/if}}
```

{% hint style="info" %}
Note: The `if/else` statements work only when added inside a single cell. For example:

<img src="/files/fuY5ILTgPq8bXQlPlD6b" alt="" data-size="original">
{% endhint %}

You can use the conditional statements in the following ways

* `if`
* `if-else`
* `if-else if`
* `if-else if-else`
* `if-else if-else if`
* `if-else if-else if-else`
* and so on...

Below are a few examples:

| <p><code>{{#if show\_payment\_details}}</code></p><p><code>ACH to {{acNumber}}</code></p><p><code>{{/if}}</code></p>                                                                                                                                                   | prints the text `ACH to xxxxxxxxx` if `show_payment_details` is present and not `false`.                                                                                                                                                               |
| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| <p><code>{{#if (payment\_status == "paid")}}</code></p><p><code>payment cleared</code></p><p><code>{{/if}}</code></p>                                                                                                                                                  | prints `payment cleared` if `payment_status` equals to `"paid"` (case-sensitive)                                                                                                                                                                       |
| <p><code>{{#if (payment\_status != "paid")}}</code></p><p><code>unpaid</code></p><p><code>{{/if}}</code></p>                                                                                                                                                           | prints `unpaid` if `payment_status` not equal to `"paid"` (case-sensitive)                                                                                                                                                                             |
| <p><code>{{#if (payment\_status == "paid")}}</code></p><p><code>paid</code></p><p><code>{{else}}</code></p><p><code>unpaid</code></p><p><code>{{/if}}</code></p>                                                                                                       | prints `paid` if `payment_status` equals to `"paid"` otherwise prints `unpaid`                                                                                                                                                                         |
| <p><code>{{#if (payment\_status == "paid")}}</code></p><p><code>paid</code></p><p><code>{{else if (payment\_status == "initiated")}}</code></p><p><code>payment initiated</code></p><p><code>{{else}}</code></p><p><code>pending</code></p><p><code>{{/if}}</code></p> | <p>prints <code>paid</code> if <code>payment\_status</code> equals to <code>"paid"</code></p><p>prints <code>payment initiated</code> if <code>payment\_status</code> equals to <code>initiated</code></p><p>otherwise prints <code>pending</code></p> |
| <p><code>{{#if (price > 1000)}}</code></p><p><code>good deal</code></p><p><code>{{/if}}</code></p>                                                                                                                                                                     | prints the text `good deal` if price is greater than 1000                                                                                                                                                                                              |
| <p><code>{{#if (price >= 1000)}}</code></p><p><code>decent deal</code></p><p><code>{{/if}}</code></p>                                                                                                                                                                  | prints text `decent deal` if price is greater than or equal to 1000                                                                                                                                                                                    |
| <p><code>{{#if (price < 1000)}}</code></p><p><code>small deal</code></p><p><code>{{/if}}</code></p>                                                                                                                                                                    | prints text `small deal` If price less than 1000                                                                                                                                                                                                       |
| <p><code>{{#if (price <= 1000)}}</code></p><p><code>okay-ish deal</code></p><p><code>{{/if}}</code></p>                                                                                                                                                                | prints text `okay-ish deal` If price less than or equal to 1000                                                                                                                                                                                        |
| <p><code>{{#if (payment\_message contains "paid")}}</code></p><p><code>Payment is cleared</code><br><code>{{/if}}</code></p>                                                                                                                                           | prints `Payment is cleared` if `payment_message` contains the text `paid` *(for example, `this invoice has been paid` contains the text `paid` in it)*                                                                                                 |
| <p><code>{{#if (payment\_message not\_contains "paid")}}</code></p><p><code>Payment is due</code><br><code>{{/if}}</code></p>                                                                                                                                          | prints `Payment is due` if `payment_message` does not contain the text `paid` *(for example, `this invoice is not cleared` does not contain the text `paid` in it)*                                                                                    |
| <p><code>{{#if (status == "open" or status == "on-hold")}}</code></p><p><code>Payment is pending</code></p><p><code>{{/if}}</code></p>                                                                                                                                 | prints `Payment is pending` if `status` is `open` OR `on-hold`                                                                                                                                                                                         |
| <p><code>{{#if (status == "open" or status == "on-hold" or status == "under review")}}</code></p><p><code>Payment is pending</code></p><p><code>{{/if}}</code></p>                                                                                                     | prints `Payment is pending` if `status` is `open` OR `on-hold` OR `under review`                                                                                                                                                                       |
| <p><code>{{#if (status != "open" and status != "on-hold")}}</code></p><p><code>Payment is not pending</code></p><p><code>{{/if}}</code></p>                                                                                                                            | prints `Payment is not pending` if `status` is not `open` AND not `on-hold`                                                                                                                                                                            |
| <p><code>{{#if (status == "open" and priority == "high")}}</code></p><p><code>High priority open task</code></p><p><code>{{/if}}</code></p>                                                                                                                            | prints `High priority open task` if `status` is `open` AND if `priority` is `high`                                                                                                                                                                     |
| <p><code>{{#if (payment\_status != "paid")}}Please Clear the Dues within 30 days</code></p><p><code>{{/if}}</code></p>                                                                                                                                                 | prints `Please Clear the Dues within 30 days` if the `payment_status` is not equal to `paid`                                                                                                                                                           |
| <p><code>{{#if (status in "open,pending")}}In Progress... Please stay tuned for further updates.</code></p><p><code>{{/if}}</code></p>                                                                                                                                 | prints `In Progress... Please stay tuned for further updates.` if `status` is sub-string of `"open,pending"`                                                                                                                                           |

#### Hiding Empty Sections & Lines

In the following example, when the `address` field has a value, it gives desired outcome. If the address is empty, it leaves an empty line in the output.

```
{{customer_name}},
{{#if address}}{{address}},{{/if}}
{{city}}, {{country}}
```

<table><thead><tr><th>Data</th><th>Output</th></tr></thead><tbody><tr><td><pre><code>customer_name = John Doe
city = NY
country = US
</code></pre></td><td><pre><code>John Doe,
NY, US
</code></pre></td></tr><tr><td><pre><code>customer_name = John Doe
street = WinWood St.
city = NY
country = US
</code></pre></td><td><pre><code>John Doe,
WinWood St.,
NY, US
</code></pre></td></tr></tbody></table>

To hide empty lines, we should open the `if` condition in previous line or close it in next line. Here are examples on how the output will look like when street address is passed and when it is not:

<table><thead><tr><th>Syntax</th><th>Data</th><th>Output</th></tr></thead><tbody><tr><td><pre><code>{{customer_name}},{{#if street}}
{{street}},{{/if}}
{{city}}, {{country}}
</code></pre></td><td><pre><code>customer_name = John Doe
city = NY
country = US
</code></pre></td><td><pre><code>John Doe,
NY, US
</code></pre></td></tr><tr><td><pre><code>{{customer_name}},{{#if street}}
{{street}},{{/if}}
{{city}}, {{country}}
</code></pre></td><td><pre><code>customer_name = John Doe
street = WinWood St.
city = NY
country = US
</code></pre></td><td><pre><code>John Doe,
WinWood St.,
NY, US
</code></pre></td></tr><tr><td><pre><code>{{customer_name}},
{{#if street}}{{street}},
{{/if}}{{city}}, {{country}}
</code></pre></td><td><pre><code>customer_name = John Doe
city = NY
country = US
</code></pre></td><td><pre><code>John Doe,
NY, US
</code></pre></td></tr><tr><td><pre><code>{{customer_name}},
{{#if street}}{{street}},
{{/if}}{{city}}, {{country}}
</code></pre></td><td><pre><code>customer_name = John Doe
street = WinWood St.
city = NY
country = US
</code></pre></td><td><pre><code>John Doe,
WinWood St.,
NY, US
</code></pre></td></tr></tbody></table>

### Iterating inside a cell

Multiple entries inside a cell can be incorporated by using the following syntax.

![Iterating a list inside a cell in Excel](/files/-MX8D-i6bpwL6ww6QuuF)

![Output for iterating a list inside a cell in Excel](/files/-MXVfA5yXu14cfBaIEi5)

## **Tables**

Dynamic tables allow a template to repeat a row for each item in a list, automatically adjusting during merging. Instead of setting a fixed number of rows, use loop tags `{{#each ...}}` ... `{{/each}}`. The result is a well-organized table—ideal for invoices, order summaries, schedules, or reports where record count changes.

Following are different ways in which a Dynamic Table can be created:

### Simple Table

A simple and straight forward table which addresses most use-cases. To create a simple table which repeat one or many rows for each item in a list, follow these instructions:

1. Identify the cell where table should start. *(ex: B3)*
2. Identify number of columns that are to be repeated as part of the Dynamic Table. *(ex: 3)*
3. Now, merge the number of cells starting from the start cell. *(ex: Merge B3 -> D3)*
4. Add the loop's opening tag `{{#each YOUR_TOKEN_NAME}}` . *(ex: `{{#each invoice_items}}` )*
5. In the next row, add the content for your columns.
   1. The content in each cell can be a dynamic placeholder (like `{{name}}`) or fixed text (like `Item Name`) or a combination (like `Item Name: {{name}}`).
   2. [Formatters/Modifiers](/document-template/formatting-your-data.md) can be used to format or style dynamic data in a cell. *(For example, adding `{{upper name}}` in B4 will display the names in uppercase.)*
   3. For *ex: consider an invoice invoice, where the item name, qty, and price are to be printed in 3 adjacent columns. Just `{{name}}` , `{{quantity}}`, and `{{price}}` in cells B4, C4 and D4*
6. If another row is to be repeated configure the next row as mentioned in 5.a. This can be done for as many rows as desired.
7. Once the repeated rows are configured, in the next row merge the cells similar to what was done in step 3. *(ex: Merge B5 -> D5)*
   1. Merged cell width should be same as the number of columns that need to be repeated. This is also same as the width of the cell where loop's opening tag is added.
8. Add the loop's closing tag `{{/each}}` in this merged cell *(ex: add `{{/each}}` in merged cell B5)*

Below is an example screenshot from an excel template which uses Dynamic table to print list of invoice line items. This example also demonstrates calculating the total price using [aggregate modifier](/document-template/formatting-your-data.md#aggregate).

![Inserting a Dynamic Table in Excel](/files/Vh1wsQ0Akoj9GtuayiV2)

{% hint style="info" %}
Note that the loop's opening cell and closing cell should be merged and span across same number of columns. The cells sand-witched in between the opening cell and closing cell will be repeated. Cells to the left and to the right will not be disturbed by dynamic table.
{% endhint %}

![Example output of a Dynamic Table in Excel](/files/kwnjtMQnoncNktAXF3eV)

### Nested Tables

A **Nested Table** is more than 1 simple table nested inside one another. Nested tables allow you to repeat a nested list of items. For example, to print a list of Departments and Employee details in each Department.

To create a nested table, follow the same instructions as explained under [Simple Tables](#simple-table). When configuring the cells after creating the opening cell, follow the same instructions atop to create a child dynamic table.

The image below depicts a Dynamic Table that iterates over a list of departments, prints the Department's name and then iterates over a list of Employees in each Department and prints their ID, Name, Designation and Salary.

<figure><img src="/files/TRMzSISEZdfn7rUsNZ5J" alt=""><figcaption><p>Nested Dynamic Tables in Excel</p></figcaption></figure>

<figure><img src="/files/0VukCgG7bmm1dClypIXW" alt=""><figcaption><p>Example output of a Nested Dynamic Tables in Excel</p></figcaption></figure>

{% hint style="info" %}
The example above shows Nested Dynamic tables with a 2 level nesting. There is currently no limit on the number of nesting levels supported.
{% endhint %}

### Legacy Tables

This section acts as a reference for templates that use older Dynamic Table syntax. This syntax has many limitations and is not recommended for use.

Syntax: `{{table:YOUR_LIST.PROPERTY_NAME}}`

Example:

* `{{table:line_items.name}}`
* `{{table:line_items.qty}}`
* `{{table:line_items.amount}}`

Here for the field named `line_items` – `name`, `amount` and `qty` are defined as the property of each `line_item`. The image below shows how this example looks like when implemented.

<figure><img src="/files/w1Kl2iqNWjTwRxCLdvJU" alt=""><figcaption><p>Legacy Dynamic Table in Excel</p></figcaption></figure>

<figure><img src="/files/8QU0uQbKv6wXv82t1FsC" alt=""><figcaption><p>Example output of a Legacy Dynamic Table in Excel</p></figcaption></figure>

{% hint style="info" %}
Legacy tables are very limited in terms of functionality. The new style Dynamic Tables are flexible, scalable and are recommended over Legacy Dynamic Tables.
{% endhint %}

## Inserting a dynamic image

This will be helpful if you want to insert dynamic image in the document.

Format : **{{insert\_image image1 width=width height=height max\_width=max\_width max\_height=max\_height}}**

* `width` (optional): Desired image width
* `height` (optional): Desired image height
* `max_width` (optional): Desired maximum width of the image
* `max_height` (optional): Desired maximum height of the image

**Example Usage**

<table><thead><tr><th width="380.8046875">Syntax</th><th>Description</th></tr></thead><tbody><tr><td><code>{{insert_image image1 width=300 height=200}}</code></td><td>The image inserted will be 300px wide and 200px tall</td></tr><tr><td><code>{{insert_image image1 width=300}}</code></td><td>Inserted image will be 300px wide, height will be auto adjusted based on the original image's aspect ratio. For example if original image is 600x500, inserted image will be 300x250.</td></tr><tr><td><code>{{insert_image image1 height=300}}</code></td><td>Inserted image will be 300px tall, width will be auto adjusted based on the original image's aspect ratio.</td></tr></tbody></table>

### Constraining Image Dimensions

Use the `max_width` and `max_height` parameters to limit image dimensions.

**Examples:**

| Syntax                                                 | Description                                                                                                                                                                                                                                                                              |
| ------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `{{insert_image image1 max_width=300 max_height=300}}` | The image will be resized to fit into a 350x350 box. Aspect ratio will be maintained. For example, if the original image is 900x600, the inserted image will be 300x200                                                                                                                  |
| `{{insert_image image1 max_height=300}}`               | The image will be resized ensuring the height doesn't go beyond 300px. Aspect ratio will be maintained. For example, if the original image is 900x600, the inserted image will be 450x300                                                                                                |
| `{{insert_image image1 max_width=300}}`                | The image will be resized ensuring the width doesn't go beyond 300px. Aspect ratio will be maintained. For example, if the original image is 900x600, the inserted image will be 300x200                                                                                                 |
| `{{insert_image image1 width=300 max_height=500}}`     | The image width will be set to 300px. If the resulting height exceeds 500px, the image will be scaled down proportionally so that the height does not exceed 500 px while maintaining its aspect ratio. For example, if original image is 400x1000, the inserted image will be 200x500   |
| `{{insert_image image1 height=500 max_width=400}}`     | The image height will be set to 500px. If the resulting width exceeds 400px, the image will be scaled down proportionally so that the width does not exceed 400px while maintaining its aspect ratio. For example, if the original image is 1200x900, the inserted image will be 400x300 |

{% hint style="info" %}
The image URL need to be either publicly accessible so Docupilot can download and insert it in the document.

If you want to send only authenticated images, link your storage account like google drive, one drive, etc from **Settings > Linked Accounts** and enable **Use For Images** option if available. All image links sent to Docupilot will be downloaded using that authenticated account.
{% endhint %}

## Adjust orientation for output PDF <a href="#types-of-merge-fields" id="types-of-merge-fields"></a>

To generate a PDF in landscape mode from an XLSX template, follow these steps:

1. Open your XLSX template and navigate to the '**Page Layout**' settings.
2. Select '**Page** **Orientation**' and choose '**Landscape**.'
3. Upload the XLSX template to Docupilot, and the output will be in landscape format when converted to PDF.

<figure><img src="/files/dBB0MYCsVVN8o0L9Q5XJ" alt=""><figcaption><p><strong>Page</strong> <strong>Orientation updated on a XLSX file</strong></p></figcaption></figure>


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://help.docupilot.app/document-template/excel-file-xlsx.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
