Navigating to job card templates
To configure job card templates, follow these steps:- Select the “Settings” module from the left navigation menu.
- Click “Modules” and select “Jobs” to open the Job Settings page.
- Choose Job Card Templates.

- The job card templates listing page will appear, displaying all existing templates.
Creating a new job card template
To create a new job card template:- On the job card templates listing page, click + New Template.

- A new job card template dialog box will appear.
- Fill in the following details:
- Template Name (Mandatory): Enter a unique name for the job card template.
- Job Category (Mandatory): Select the relevant job category from the dropdown menu.
- Template Description (Mandatory): Provide a brief description of the template.
- Format (Mandatory): Choose the document size from the available options:
- A3
- A4
- A5
- Letter
- Legal
- Tabloid
- Orientation (Mandatory): Select either Landscape or Portrait.
- Border Settings (Mandatory): Define the margins for the job card layout:
- Top Border (e.g., 10mm)
- Right Border (e.g., 10mm)
- Bottom Border (e.g., 10mm)
- Left Border (e.g., 10mm)
- Click Proceed to move to the template editor.

- Table: Add tables to organize and display information in a structured manner.
- Field Components – Easily search for and insert default system fields like:
- Work Order Number
- Job Priority
- Job Description
- Customer Email
- Assigned to FE and more.


Editing a job card template
To modify an existing job card template:- Navigate to the job card templates listing page.
- Click the pencil icon next to the specific template.

- The template editor will open.
- Make the necessary changes.
- Click Save to update the template.
Deleting a job card template
If a job card template is no longer needed, follow these steps to delete it:- Navigate to the job card templates listing page.
- Click the delete icon next to the template you want to remove.

- A confirmation dialog box will appear.
- Click Delete to permanently remove the job card template.
Using dynamic variables in job card templates
{{ }}. Expressions that open a block — such as a loop or a condition — also need a closing tag. For example, {{#each checklist}} opens a loop and {{/each}} closes it. A missing closing tag is one of the most common causes of a template not rendering correctly.Before you start Two building blocks appear throughout every pattern in this article.
- A field is any piece of job data you want to display — for example,
{{job_title}}or{{customer.customer_first_name}}. - A helper is a built-in function that lets you loop through a list, compare values, split text, or format a date before it renders.
| Helper | Purpose |
|---|---|
{{#each array}} | Loop any array |
{{#eachLastInstance array "key"}} | Return only the latest entry in an array by key |
{{#if field}} | Render content only if the field has a value |
{{#stringEq a "b"}} | Match strings — loose, not case-sensitive |
{{#stringEqStrict a 'b'}} | Match strings — strict and case-sensitive |
{{#split field ','}} | Split a string and loop each part |
{{.}} | The current value inside a {{#split}} or {{#each}} loop |
{{../field}} | Access a field from the parent scope |
{{formatDateWithTimeZone date "MM/DD/YYYY" timezone}} | Format a date with a time zone |
Patterns
Pattern 1 — Checklist loop and question matching
Pattern 1 — Checklist loop and question matching
{{#each checklist}}, then use {{#stringEqStrict question 'Your Question Name'}} to target the exact question you want. Add one block per question you need to display.Key fields: checklist, question, answerExample 1 — Display a photo answerUse this example when your checklist question captures one or more photos. Zuper stores photo answers as a comma-separated list of image links, so the template splits that list and renders each image individually.
Example 2 — Display a text remarks answerUse this example when your checklist question captures a free-text response. Zuper stores multi-line text answers with a line break between each entry, so the template splits on that break and wraps each line in its own paragraph.
Pattern 2 — Service task and asset inspection: label field lookup
Pattern 2 — Service task and asset inspection: label field lookup
service_tasks / assets, label, valueService task versionWhat each line does:
| Expression | What it does |
|---|---|
{{#each service_tasks}} | Opens the loop — goes through every service task on the job, one at a time |
{{#stringEqStrict service_task_title "ROOF INSPECTION"}} | Finds the specific service task you want by matching its title exactly |
{{#if asset_inspection_submission_uid}} | Checks that an inspection form has been submitted for this service task — skips the task if nothing was filled in |
{{#if asset_inspection_submission_uid.data}} | Checks that the submitted form contains field data before trying to display anything |
{{#each asset_inspection_submission_uid.data}} | Opens the inner loop — goes through every field in the inspection form, one at a time |
{{#stringEqStrict label "Shingle Type:"}} | Finds the specific field you want by matching its label exactly |
{{#if value}}{{value}}{{/if}} | Displays the field value only if one exists — leaves no blank gap if the field was not filled in |
Asset versionWhat each line does:
| Expression | What it does |
|---|---|
{{#each assets}} | Opens the loop — goes through every asset on the job, one at a time |
{{#if asset_inspection_form_submission_uid}} | Checks that an inspection form has been submitted for this asset — skips the asset if nothing was filled in |
{{#each asset_inspection_form_submission_uid.data}} | Opens the inner loop — goes through every field in the inspection form, one at a time |
{{#stringEqStrict label "Time Gas Leak Detector Used:"}} | Finds the specific field you want by matching its label exactly |
{{#if value}}{{value}}{{/if}} | Displays the field value only if one exists — leaves no blank gap if the field was not filled in |
Pattern 3 — Asset inspection: pass, fail, and N/A
Pattern 3 — Asset inspection: pass, fail, and N/A
asset_inspection_submission_uid.data, label, value.badge-pass, .badge-fail, and .badge-na in your template’s CSS section to apply colors to each result badge. Copy the example below into your template’s CSS section to get started. Adjust the colors to match your brand.Pattern 4 — Job status: render sections by current status
Pattern 4 — Job status: render sections by current status
{{#eachLastInstance}} helper handles this — it returns only the most recent status entry so the right section renders every time.Key fields: job_status, status_name{{#stringEq status_name "..."}} blocks for any custom statuses in your workflow.Pattern 5 — Dynamic checklist: type-based rendering
Pattern 5 — Dynamic checklist: type-based rendering
checklist, question, answer, type| Type value | Renders as |
|---|---|
HEADER | Skipped — no row rendered |
IMAGE | Single image |
MULTI_IMAGE | Multiple images, split by comma |
MULTI_ITEM | Multiple paragraphs, split by comma |
MULTI_LINE | Multiple paragraphs, split by comma |
SIGNATURE | Signature image, split by comma |
SINGLE_ITEM | Single paragraph, split by comma |
| Any other value | Plain text |
Example 1 — Display a specific checklist answer as textUse this when you want to show the answer to one specific checklist question as plain text in your document. In this example, the question is “Work completed notes.”
Example 2 — Display a specific checklist answer as an imageUse this when the answer to a checklist question is a photo captured by the field executive. In this example, the question is “Site photo.”
"Site photo" with the exact question text from your checklist.Pattern 6 — Common job variables
Pattern 6 — Common job variables
| Field name | Placeholder |
|---|---|
| Work order number | {{work_order_number}} |
| Job title | {{job_title}} |
| Job description | {{job_description}} |
| Job category | {{job_category.category_name}} |
| Scheduled start time | {{scheduled_start_time}} |
| Scheduled end time | {{scheduled_end_time}} |
| Field name | Placeholder |
|---|---|
| First name | {{customer.customer_first_name}} |
| Last name | {{customer.customer_last_name}} |
| Email address | {{customer.customer_email}} |
| Mobile number | {{customer.customer_contact_no.mobile}} |
| Field name | Placeholder |
|---|---|
| Street | {{customer_address.street}} |
| City | {{customer_address.city}} |
| State | {{customer_address.state}} |
| ZIP code | {{customer_address.zip_code}} |
| Field name | Placeholder |
|---|---|
| First name | {{user.first_name}} |
| Last name | {{user.last_name}} |
| Work phone number | {{user.work_phone_number}} |
| Field name | Placeholder |
|---|---|
| Organization name | {{organization.organization_name}} |
{{#if field}}...{{/if}} before adding it to your template. This prevents empty gaps in your document when a field has no value on a particular job.Pattern 7 — Date formatting
Pattern 7 — Date formatting
formatDateWithTimeZone to display any date field in a readable format. Always pass timezone as the third argument so dates display in the customer’s local time zone.Syntax: {{formatDateWithTimeZone field "FORMAT" timezone}}| Format token | Example output |
|---|---|
MM/DD/YYYY | 04/29/2026 |
MM-DD-YYYY | 04-29-2026 |
MM/DD/YYYY hh:mm A | 04/29/2026 02:30 PM |
dddd, MMMM DD, YYYY | Wednesday, April 29, 2026 |
timezone is a job-level field that Zuper populates automatically. Omitting it causes dates to display in UTC instead of the customer’s local time zone.Pattern 8 — Custom fields
Pattern 8 — Custom fields
custom_fields, label, value, type, group_nameExample 1 — Display a specific custom field by nameUse this example when you want to display one specific custom field — for example, the invoice amount paid on a job. The template finds the field by matching its exact label and displays its value.
| Expression | What it does |
|---|---|
{{#each custom_fields}} | Opens the loop — goes through every custom field on the job, one at a time |
{{#if group_name}}{{else}} | Skips any fields that belong to a group — targets only standalone fields |
{{#stringEqStrict label "Invoice amount paid"}} | Finds the specific field by matching its label exactly |
{{#if value}}{{value}}{{/if}} | Displays the value only if one exists — leaves no blank gap if the field was not filled in |
Example 2 — Display all fields of a specific typeUse this example when you want to display all custom fields of a given type — for example, all time fields or all multi-line text fields. The template loops through every custom field and renders each one that matches the type you specify.
| Expression | What it does |
|---|---|
{{#each custom_fields}} | Opens the loop — goes through every custom field on the job, one at a time |
{{#if value}} | Skips any fields with no value — prevents blank rows in your document |
{{#stringEqStrict type "TIME"}} | Matches all fields of the TIME type and formats the value as a readable time |
{{formatCustomDate value "hh:mm A" "hh:mm A"}} | Formats the time value — for example, 02:30 PM |
{{#stringEqStrict type "MULTI_LINE"}} | Matches all fields of the MULTI_LINE type and displays the value as a paragraph |
{{#stringEqStrict type "LOOKUP"}} | Matches all fields of the LOOKUP type and displays the selected value |
Example 3 — Display fields from a specific group by labelUse this example when your custom fields are organized into groups in Zuper — for example, a group called “Payment Details” that contains fields like “Invoice amount paid” and “Payment method.” The template finds the group by name, then looks up the specific field you want by its label.
| Expression | What it does |
|---|---|
{{#each custom_fields}} | Opens the loop — goes through every custom field on the job, one at a time |
{{#if group_name}} | Checks whether the field belongs to a group — skips standalone fields |
{{#stringEqStrict group_name "Payment Details"}} | Finds the specific group by matching its name exactly |
{{#stringEqStrict label "Invoice amount paid"}} | Finds the specific field within the group by matching its label exactly |
{{#if value}}{{value}}{{/if}} | Displays the value only if one exists — leaves no blank gap if the field was not filled in |
Pattern 9 — Parent scope with ../
Pattern 9 — Parent scope with ../
../ before a field name to step out one level and pull in fields from the job level — for example, the job title or work order number.| Prefix | Accesses |
|---|---|
| (none) | Current loop scope |
../ | One level up |
../../ | Two levels up |
FAQs
Why is a field showing as blank in my rendered document?
Why is a field showing as blank in my rendered document?
../ prefix to reach the parent scope. Wrap the field in {{#if field}}...{{/if}} to confirm whether it has a value. If you are inside a {{#each}} block, add ../ before the field name and test again. If the issue continues, contact Support.Why is my job status section repeating multiple times?
Why is my job status section repeating multiple times?
{{#eachLastInstance job_status "status_name"}} and not {{#each job_status}}. Plain {{#each}} repeats the section for every status the job has ever had. {{#eachLastInstance}} shows only the current one. Second, confirm your {{#stringEq status_name "..."}} filter is present and the status name matches exactly what appears in Zuper — including capitalization. A missing or mismatched filter causes the section to show nothing or display the wrong content.What is the difference between {{#stringEq}} and {{#stringEqStrict}}?
What is the difference between {{#stringEq}} and {{#stringEqStrict}}?
{{#stringEq}} performs a loose match and is not case-sensitive. Use it for status name comparisons such as “Completed” or “Scheduled.” {{#stringEqStrict}} performs an exact, case-sensitive match. Use it when matching question names, inspection labels, or result values such as “Pass,” “Fail,” or “N/A.”Can I nest patterns inside each other?
Can I nest patterns inside each other?
How do I display a date in the customer's local time zone?
How do I display a date in the customer's local time zone?
{{formatDateWithTimeZone field "FORMAT" timezone}}. Always include timezone as the third argument — it is a job-level field that Zuper populates automatically. Omitting it causes dates to display in UTC instead of the customer’s local zone. See Pattern 7 for format token examples.Related articles
- Configuring Job Card Templates — Create and manage job card document templates
- Configuring Job Checklist — Set up checklist questions that appear on jobs
- Configuring Service Tasks — Configure service tasks and attach inspection forms
- Configuring Inspection Forms — Create and manage asset-level inspection forms
- Configuring Job Custom Fields — Add and configure job-level custom fields