Note: ZAT is in maintenance mode. For the best experience, use the Zendesk Command Line Interface (ZCLI) to develop Zendesk apps.

The Apps framework gives you a lot of freedom. For example, you can use Bootstrap for styling, Handlebars for templating, and jQuery for scripting. Or you can choose an entirely different set of resources, or write your own.

This tutorial shows you how to apply your choices to the default project files created by the Zendesk Apps Tools (ZAT). You can save and reuse the project files in other projects, or use the same techniques to create your own set of reusable files.

This tutorial covers the following topics:

If you're an experienced client-side web developer, you can use the App Scaffold on Github as a starting point. It includes Bootstrap, Handlebars, jQuery, Moment.js, and lodash. It also supports ESLint, NPM, and webpack. See the App Scaffold's folder structure. Make sure to remove the legacy shims in src/javascripts/base_app.js.

Minimum file requirements

To upload and install an app in a Zendesk application, you must meet the following minimum file requirements. Everything else is optional. For example, the rest of the app can be hosted on a remote application server, including the HTML file to be iframed into the Zendesk application.

File requirements

  • The manifest.json file must exist in the root folder of the app. See Manifest.

  • A translation file named {locale}.json must exist in a folder named translations in the root folder. The value of {locale} is specified by the defaultLocale property in manifest.json. For example, if "defaultLocale" is "en", then make sure a file named en.json exists in the translations folder. See i18n.

  • An app icon named logo-small.png should be included in a folder named assets in the root folder. The image is used in the header of the app. You can still upload and install the app without it, but a broken image icon will appear in the app's header. See App icon for the image specifications.

  • An app tile named logo.png should be included in the assets folder. The image is used in the product admin pages for managing apps. You can still upload and install the app without it but a broken image icon will appear in the interface. See App tile for the image specifications.

  • If you plan on making the app available in the Zendesk Marketplace (as opposed to creating a private app to run only in your Zendesk account), additional branding assets may be required. See Branding.

Create the files

Before you start, make sure you have the latest version of the Zendesk Apps Tools (ZAT). See Installing and using the Zendesk Apps Tools. If you already have ZAT, run the following command to get the latest updates:

$ gem update zendesk_apps_tools

To create a basic set of files for the app

  1. If not already done, create a project folder for your apps.

  2. Open your command-line interface and navigate to the new folder.

  3. Run the following command at the prompt:

    $ zat new
  4. When prompted, enter the following information:

    • author's name - your name
    • author's email - your email
    • author's url - your website url if you have one, or press Enter to leave it blank
    • app name - Project Starter
    • iFrame URI - press Enter to leave it blank. You'll use the default iframe file created by ZAT
    • directory name - project_starter

After you're done, the tool creates files for a new app.

The tool also records properties about the app in the manifest.json file, including the host application (Zendesk Support), the app's location in the host (ticket sidebar), and the path to the file to be iframed in the host (assets/iframe.html). Example:

"location": {   "support": {     "ticket_sidebar": "assets/iframe.html"   }},...

Import libraries

You can write everything from scratch yourself but it's much easier to use existing libraries. You can import whatever library you want in your projects, but in this example you'll import jQuery, Handlbars, and Bootstrap.

While you can use any custom CSS or a front-end framework like Bootstrap for the look and feel of your app, Zendesk recommends using Zendesk Garden. Zendesk Garden is designed to be a common baseline of styles and components between all Zendesk products. If you want your app to match the Zendesk look and feel, use Zendesk Garden CSS classes and React components in your app.

You can import Zendesk Garden CSS classes and React components into your app's HTML template from the jsDelivr CDN. See The jsDelivr files are npm packages that can also be installed from npm. See

For more information about the CSS classes and React components in Zendesk Garden, see or the demo app.

To import libraries

  1. In a text editor, open the assets/iframe.html file.

  2. Link to the Bootstrap CSS by replace the Zendesk Garden tag with the following Bootstrap tag in the <head> tag:

    <head><link href="" rel="stylesheet"></head>...

    You decide what version of the Bootstrap CSS you want to use.

  3. Import the jQuery, Handlebars, and Bootstrap JS libraries by adding the following <script> tag after the <h2> tag in the body:

    ...<script src="[email protected],[email protected],[email protected]"></script>

    Note: As of this writing, a newer version of jQuery is available (3.0.0), but the Bootstrap library only supports jQuery versions below 3.0.

    You can use a service like jsdelivr to import all your libraries from one CDN in one tag, or you can import the libraries from whatever source you like. Example:

    <script src=""></script><script src=""></script>

Add your own CSS file

The Bootstrap CSS gives you a huge number of options but you'll inevitably need to modify the styles for your projects.

  1. Create a file named main.css file in the assets folder.

  2. In the <head> tag in iframe.html, add the following stylesheet link after the Bootstrap link:

    <head>  ...  <link href="main.css" rel="stylesheet"></head>

Add your own JS file

It's best practice to keep your JavaScript separate from your HTML.

  1. Create a file named main.js file in the assets folder.

  2. Add the following function, which duplicates the JavaScript code in iframe.html:

    $(function() {  var client = ZAFClient.init();  client.invoke('resize', { width: '100%', height: '400px' });});

    This jQuery statement defines a self-invoking, anonymous function that runs after iframe.html has finished loading in the browser.

  3. In iframe.html, replace the following <script> tag:

    <script>// Initialise the Zendesk JavaScript API client// client = ZAFClient.init();client.invoke('resize', { width: '100%', height: '400px' });</script>

    with the following tag:

    <script type="text/javascript" src="main.js"></script>

    Make sure the tag is after all the other script tags to ensure the imported libraries are loaded in memory before the browser reaches your script.

  4. Save both files.

Create and display a starter template

In Handlebars, you create templates by including the markup in <script> tags in the main HTML file. You display the template content by inserting it at runtime into an element in the DOM. You decide to use a div tag for your template content.

Another option is to store the markup in separate .hdbs files in the assets folder, then compile them at runtime. To learn how, see this Gist by Daniel Pawluk. Note that he calls the function switchView() and that it requires a <div id="view_container"></div> on the main iframe.

Note: You can also precompile templates, but that's beyond the scope of this tutorial. For more information, see How to Precompile Handlebars Templates.

  1. In iframe.html, replace the <h2> heading, "Zendesk Apps Tools Iframe Scaffold", which you don't need, with the following div tag:

    <div id="content"></div>

    This is where the template content will be inserted at runtime.

  2. Still in the iframe.html file, add the following template before all the other <script> tags:

    <script id="start" type="text/x-handlebars-template">  <p>Hello, {{name}}!</p></script>

    The template markup consists of a simple message with one template expression, {{name}}, which will be replaced with a value at runtime.

  3. Switch to main.js and add the following showStart() function definition to the file:

    function showStart() {  var context = {     name: 'world'  };  switchTo('start', context);}

    This function defines the context, or data, for the template, and then calls the switchTo() helper function, which you'll create next. The switchTo() function takes 2 arguments: the id of the script tag containing the template, and the context.

    You can change the value of the name property to anything you want.

  4. Add the following switchTo() helper function definition:

    function switchTo(template_name, context) {  var template_id = "#" + template_name;  var source = $(template_id).html();  var template = Handlebars.compile(source);  if (context) {    var html = template(context);  } else {    var html = template();  }  $("#content").html(html);}

    This helper function generates and inserts the HTML from any template into your iframe.html file at runtime. Here's how it works:

    • The first line gets the id of the <script> tag that contains the template.
    • The second line gets the template markup.
    • The third line compiles the template.
    • The if block generates the final HTML. Some templates don't have a context, so the function includes an if clause to handle the case.
    • The final line sets the HTML content of the <div> tag with an id of content.
  5. Add a call to the showStart() function in the self-invoking function at the top of the file:

    $(function() {  ...  showStart();});

    When the HTML file has finished loading in the browser, the anonymous function runs the showStart() function, which displays a start page in the user interface.

  6. Save both files.

Completed project starter files

The main.js file should look as follows:

$(function() {  var client = ZAFClient.init();  client.invoke('resize', { width: '100%', height: '400px' });  showStart();});
function showStart() {  var context = {    name: 'world'  };  switchTo('start', context);}
function switchTo(template_name, context) {  var template_id = "#" + template_name;  var source = $(template_id).html();  var template = Handlebars.compile(source);  if (context) {    var html = template(context);  } else {    var html = template();  }  $("#content").html(html);}

The iframe.html file should look as follows:

<html><head>  <link href="" rel="stylesheet">  <link href="main.css" rel="stylesheet"></head><body>  <div id="content"></div>
  <script id="start" type="text/x-handlebars-template">    <p>Hello, {{name}}!</p>  </script>
  <script src="[email protected],[email protected],[email protected]"></script>  <script type="text/javascript" src=""></script>  <script type="text/javascript" src="main.js"></script></body></html>