> ## Documentation Index
> Fetch the complete documentation index at: https://kb.mspprocess.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Report templates and reports

> Design a Handlebars report template, fill it from a workflow with Generate Report, then view, download or share the report with a password-protected link.

Reporting turns workflow data into a web page you can share with a client: a template sets the layout, and a workflow's Generate Report step fills it in. Anyone who can open Reporting, which includes [Admins and Approvers](https://kb.mspprocess.com/studio/clients/team-and-permissions.md#roles), can create and edit templates.

<video controls preload="none" playsInline poster="/images/videos/studio-reports.jpg" src="https://mintcdn.com/triggr/GxrCQFDFNLmEMyJ1/images/videos/studio-reports.mp4?fit=max&auto=format&n=GxrCQFDFNLmEMyJ1&q=85&s=b3f8d1ce919e67c63c9891896a7631a0" />

Reports: designing a template, filling it from a workflow, then viewing and sharing the report (1:25).

![The Templates page, Manage your reporting templates, with Refresh and New Template buttons, a Search templates box and one template, Docs sample – Monthly client summary, type html, created Oct 16, 2026, with Edit and delete actions.](https://mintcdn.com/triggr/XztmSfsoAUpshfIO/images/studio/reporting/templates.png?fit=max\&auto=format\&n=XztmSfsoAUpshfIO\&q=85\&s=d72d53d7c4a26882d4c3b3ce623d8fae)

## Example: a monthly client summary

**1. Create the template**

Go to **Reporting > Templates**, click **New Template**, name it, keep the type on HTML and paste the template into the editor:

```handlebars theme={null}
<style>
  body { font-family: Arial, sans-serif; color: #1f2937; background: #ffffff; padding: 24px; }
  table { border-collapse: collapse; width: 100%; }
  th, td { text-align: left; padding: 6px 10px; border-bottom: 1px solid #e5e7eb; }
  .failed { color: #b91c1c; font-weight: bold; }
</style>
<h1>{{client}}: IT summary for {{month}}</h1>
<p>We closed <strong>{{tickets.closed}}</strong> of {{tickets.opened}} tickets this month.</p>
<h2>Backups</h2>
<table>
  <tr><th>Device</th><th>Last backup</th><th>Result</th></tr>
  {{#each backups}}
  <tr>
    <td>{{device}}</td>
    <td>{{lastBackup}}</td>
    <td>{{#if ok}}OK{{else}}<span class="failed">Failed</span>{{/if}}</td>
  </tr>
  {{/each}}
</table>
{{#if notes}}<p>{{notes}}</p>{{/if}}
```

**2. Preview it with sample data**

Click **Preview Context**, paste data shaped like your workflow's and click **Apply & Close**.

```json theme={null}
{
  "client": "Acme Corp",
  "month": "September 2026",
  "tickets": { "opened": 42, "closed": 39 },
  "backups": [
    { "device": "ACME-DC01", "lastBackup": "2026-09-30 23:10", "ok": true },
    { "device": "ACME-NAS01", "lastBackup": "2026-09-28 23:40", "ok": false }
  ],
  "notes": "ACME-NAS01 missed two backups. We've replaced its disk and are watching it."
}
```

![The Handlebars Preview Context dialog, Enter JSON data to use for previewing your Handlebars template, containing the Acme Corp sample data, with Close and Apply & Close buttons.](https://mintcdn.com/triggr/XztmSfsoAUpshfIO/images/studio/reporting/preview-context.png?fit=max\&auto=format\&n=XztmSfsoAUpshfIO\&q=85\&s=c32ab9ec595c8a99e81b841a2bb308d2)

The preview beside the editor shows the result. Click **Create Template**.

![The Create New Template dialog: name Docs sample – Monthly client summary, Template Type HTML, the template in the Template Editor with How Templating Works, Apply Base Template, Preview Context and Hide Preview above it, and a preview showing Acme Corp: IT summary for September 2026 with a backups table where ACME-NAS01 is Failed in red.](https://mintcdn.com/triggr/XztmSfsoAUpshfIO/images/studio/reporting/template-editor.png?fit=max\&auto=format\&n=XztmSfsoAUpshfIO\&q=85\&s=51c8be89f3cfe3ffca7bb711210b5795)

**3. Generate it from a workflow**

Add **Generate Report** from Reporting, choose the template, enter a report name and put the data in Parameters; here `{{ ctx.params | json }}` passes everything the trigger received.

![The Generate Report step: Template Docs sample – Monthly client summary, Report Name built from ctx.params.client and month, Visibility Shareable Externally, Password sample-only and Parameters ctx.params with the json filter.](https://mintcdn.com/triggr/XztmSfsoAUpshfIO/images/studio/reporting/generate-report-step.png?fit=max\&auto=format\&n=XztmSfsoAUpshfIO\&q=85\&s=dde9d9e63f69aa32ecd127b4b4941006)

Visibility is Internal Only (your team, in Studio) or Shareable Externally (a public link), with an optional password; neither can change once the report exists.

**4. Test it**

Save, click **Manual Trigger** and enter the sample data from step 2. The output has the new report's `reportId`.

![The Generate Report step in a run: Status success, Type generate\_report and Output with status success, message Report generated successfully, reportId, createdAt, reportName Acme Corp: IT summary for September 2026 and visibility shareable.](https://mintcdn.com/triggr/XztmSfsoAUpshfIO/images/studio/reporting/generate-report-output.png?fit=max\&auto=format\&n=XztmSfsoAUpshfIO\&q=85\&s=19bf95d5f1356dad51a7ac265002f85d)

In a real workflow, fill Parameters from earlier steps, such as a ticket count from your PSA and backup results from your backup tool, and run it on the 1st of each month with a [Cron trigger](https://kb.mspprocess.com/studio/workflows/triggers.md#cron) such as `0 7 1 * *`.

## Template syntax

Templates use [Handlebars](https://handlebarsjs.com/guide/) and see exactly the JSON object in Parameters.

| Write | To |
| - | - |
| `{{client}}`, `{{tickets.closed}}` | Insert a value, made safe for HTML |
| `{{{notesHtml}}}` | Insert a value as HTML, unchanged |
| `{{#each backups}}…{{/each}}` | Repeat for each item: `{{device}}` is the item's field, `{{this}}` the item, `{{@index}}` its position |
| `{{#if ok}}…{{else}}…{{/if}}` | Show one part or the other; `{{#unless}}` is the opposite |
| `{{#with tickets}}{{closed}}{{/with}}` | Read fields of one object |

Do sums and date formatting in a Code step before Generate Report and pass the results in Parameters. A Markdown template is filled the same way, then turned into HTML.

## Reports

Reporting > Reports lists every generated report. Click **View** to open one; Download Report saves it as an HTML file, and Show in the Password column reveals a shareable report's password.

![The Reports page, View and manage generated reports, with Search reports, an All Visibilities filter and one report, Acme Corp: IT summary for September 2026, Shareable Externally, a hidden password with Show, the created date, and Share, View and delete actions.](https://mintcdn.com/triggr/XztmSfsoAUpshfIO/images/studio/reporting/reports.png?fit=max\&auto=format\&n=XztmSfsoAUpshfIO\&q=85\&s=8df6d15a5f1eb6aa5694aefab40c6789)

![A report open from View, titled Acme Corp: IT summary for September 2026 with a Download Report button, showing the tickets sentence, the backups table and the notes line.](https://mintcdn.com/triggr/XztmSfsoAUpshfIO/images/studio/reporting/view-report.png?fit=max\&auto=format\&n=XztmSfsoAUpshfIO\&q=85\&s=6bf7af9fcdecc99d3e1a197d7f7373a1)

### Share a report

Click **Share** on a shareable report and copy the link. It uses your custom forms domain if you have one ([Branding](https://kb.mspprocess.com/studio/settings/branding-and-portal.md)).

![The Share Report dialog with a Public Report URL starting https://forms.yourmsp.com/telescope/reports/, a Copy button and Open in new tab.](https://mintcdn.com/triggr/XztmSfsoAUpshfIO/images/studio/reporting/share-report.png?fit=max\&auto=format\&n=XztmSfsoAUpshfIO\&q=85\&s=7784e7bd613a563a4439a865d72e9285)

Recipients enter the password, if there is one, then see the report under your Dark Mode Logo, or your display name if you haven't uploaded one:

![A public report page for Acme Corp: IT summary for September 2026 saying This report requires a password to access, with a Password box and an Access Report button.](https://mintcdn.com/triggr/XztmSfsoAUpshfIO/images/studio/reporting/public-report-password.png?fit=max\&auto=format\&n=XztmSfsoAUpshfIO\&q=85\&s=42b59128eba7915eda01beb125dea671)

![The public report with a black header showing Your MSP, the report name, the generated date and Download, above the Acme Corp summary.](https://mintcdn.com/triggr/XztmSfsoAUpshfIO/images/studio/reporting/public-report.png?fit=max\&auto=format\&n=XztmSfsoAUpshfIO\&q=85\&s=ca43183ea413f79c270787a1b24a9bf1)

To email the link from the workflow, add a Send Email step after Generate Report with `https://forms.yourmsp.com/telescope/reports/<org-id>/{{ ctx.steps['Generate Report'].reportId }}`, using your forms domain (or `app.triggr-app.com`) and your organisation's ID from Support > Copy Org ID in the top bar. Send the password separately.

A report is a snapshot: editing the template changes only reports generated afterwards. To withdraw a report, delete it.

## FAQ

> [accordion] Can I make PDF reports?
>
> Reports are web pages; recipients can download the page or print it to PDF from their browser.

> [accordion] Can the template read the client or today's date?
>
> Only if you pass them in Parameters, such as `"client": "{{ ctx.client.name }}"`.

> [accordion] My report shows dark text on a dark background in Studio
>
> Set a background colour in the template, as the example does with `background: #ffffff`.

> [accordion] Can an AI assistant build templates or reports?
>
> Yes, through [MCP](https://kb.mspprocess.com/studio/mcp.md) with the Report Templates and Reports tools, such as `create_report_template` and `generate_report`.

> [accordion] I need slides rather than a page
>
> Use [Decks](https://kb.mspprocess.com/studio/reporting/decks.md).

## Troubleshooting

> [accordion] “parameters must be valid JSON”
>
> Parameters isn't a JSON object once its templates are filled in. Put quotes around text values, as in `"client": "{{ ctx.client.name }}"`, or use `| json`.

> [accordion] “failed to render HTML template: …” or “failed to render markdown template”
>
> The template has a Handlebars mistake, such as an `{{#each}}` without `{{/each}}`. Check it with sample data in the template's preview.

> [accordion] “template not found or does not belong to the specified organization”
>
> The step's template was deleted. Choose another in the step and save.

> [accordion] A value is blank in the report
>
> The name in the template doesn't match Parameters: `{{tickets.closed}}` needs `"tickets": { "closed": … }`. Names are case-sensitive.

> [accordion] Share is missing on a report
>
> The report is Internal Only. Generate it again with Visibility set to Shareable Externally.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.