Zendesk apps in the nav bar and top bar locations display a related app icon. In this tutorial, you'll create a top bar app that dynamically updates its icon based on a changing integer. The integer represents a count of unread messages from a third-party API.

To change the icon, the app runs a background instance. This background instance accesses the app's top bar instance using the client.instance() method. This lets the app change the icon even when the top bar app is closed.

Note: Dynamic app icons are not supported in the ticket editor location because the iconSymbol API used to create them is not supported in that location.

What you'll need

To complete this tutorial, you'll need the following:

Creating the app files

First, create basic starter files for an app named Message Counter.

  1. In your shell, navigate to the folder where you want to store the app. Example:

    cd projects
  2. In the folder, run:

    zcli apps:new
  3. At the prompts, enter the following values:

    • Directory name: msg_counter
    • Author's name: Your name
    • Author's email: Your email address
    • Author's website: Leave blank and press Enter.
    • App name: Message Counter

    ZCLI creates app starter files in the Message Counter folder.

Setting the app locations

Next, update the app to run in the top bar and background locations.

  1. In the msg_counter folder, open manifest.json in your text editor.

  2. Replace the location property with the following:

    ..."location": {  "support": {    "top_bar": {      "url": "assets/iframe.html"    },    "background": "assets/iframe.html"  }},...
  3. Save manifest.json.

Adding the top bar icon

Top bar apps require an SVG app icon named icon_top_bar.svg. To add the app icon, right-click the following image link and save it to your computer as icon_top_bar.svg. Place the image in the msg_counter/assets folder.

How app icon changes work

The above icon_top_bar.svg file includes multiple icons as <symbol> tags. Each <symbol> tag has a unique id attribute.

<svg xmlns="http://www.w3.org/2000/svg">  <symbol id="default" viewBox="0 0 990 990" ...>    ...  </symbol>  <symbol id="count-1" viewBox="0 0 990 990" ...>    ...  </symbol>  ...</svg>

When a top bar app starts, it uses the symbol with the "default" id. To change the icon, you can use the top bar instance's ZAF client to set the iconSymbol property.

client.set("iconSymbol", "count-1")

Dynamically setting the top bar icon

Update your app to dynamically change its icon based on data.

For this tutorial, you'll use a JavaScript function to generate a random integer between 0–10 (inclusive). The integer represents a count of unread messages. In a production app, you could update the function to get similar data from a third-party API using the client.request() method.

  1. In the app's assets folder, open iframe.html. Replace the <script> tag containing ZAFClient.init() with the following:

    <script type="text/javascript" src="main.js"></script>
  2. In the assets folder, create a main.js file. Paste the following into the file:

    const client = ZAFClient.init();const POLL_INTERVAL_IN_MILLIS = 2000;
    async function updateIconCount(delayInMillis) {  const count = await getCount();
      if (count > 9) {    setTopBarIcon("count-9plus");  } else if (count === 0) {    setTopBarIcon("default");  } else {    setTopBarIcon(`count-${count}`);  }  await new Promise((resolve) => setTimeout(resolve, delayInMillis));  await updateIconCount(delayInMillis);}
    // In prod, update this function to call a// third-party API using ZAF's client.request() methodasync function getCount() {  // Returns a random integer between 0-10 (inclusive)  return Math.floor(Math.random() * 11);}
    async function setTopBarIcon(symbol) {  const topBar = await getTopBarInstance();  topBar.set("iconSymbol", symbol);}
    async function getTopBarInstance() {  const instancesData = await client.get("instances");  const instances = Object.values(instancesData.instances);  const topBar = instances.find((e) => e.location === "top_bar");  return client.instance(topBar.instanceGuid);}
    client.on("app.registered", (appData) => {  const location = appData.context.location;  if (location === "background") {    updateIconCount(POLL_INTERVAL_IN_MILLIS);  }});

    Most of the code only runs in the app's background instance. When the background instance loads, it generates a message count.

    The background instance then uses the client.instance() method to access the top bar instance's ZAF client. The background instance uses this client to set the iconSymbol property. This changes the icon to one that corresponds to the message count.

    Every two seconds, the background instance generates a new message count and updates the icon.

  3. Save iframe.html and main.js.

Running the app locally

Run the app locally to ensure it changes the top bar icon every two seconds.

  1. In your shell, navigate to the msg_counter folder. Example:

    cd projects/msg_counter
  2. Start a local ZCLI web server.

    zcli apps:server

    Note: To stop the server, press Ctrl+C.

  3. In your browser's private or incognito window, sign in to Zendesk Support and go to the Agent Workspace. Append ?zcli_apps=true to the URL. Example:


  4. The top bar displays the app icon. The app automatically changes the icon every two seconds.

Next steps

Congratulations! You've created an app that dynamically updates its icon. As a next step, consider the following tasks:

  • Change the app's getCount() function to call a third-party API using the client.request() method
  • Update the top bar app to display useful information from the API
  • Add error handling for the app's async calls
  • Upload and install the app as a private app in your Support instance