Auto refresh a Tableau Dashboard without Embedding
March 21, 2017
, , , , ,

counterI was casually sitting at my desk writing my first ever blog entry here when Tamás Földi walked past my desk. He asked me how much I know about Tableau and JavaScript, because he has a cool idea which he didn’t really manage to find the time to implement yet. He quickly briefed me into what he had in mind and off I went to start coding it. The idea is to place a little spinner or counter into a Tableau Dashboard and as often as the counter ticks call the refresh JavaScript API function to reload the data. All this without embedding the dashboard into an another page. And what if I tell you that this little gem can be reused without any changes in any Dashboards on any Server? I bet you want to see it action first, right? I knew that, so click here to see a live working demo. If you like what you see I’m sure you’ll also enjoy reading the rest of the post where I share how it’s all put together.

TL;DR – Auto refresh Tableau dashboard

We’ve developed it using the Tableau Web Data Connector trick explained here. Download and deploy this data connector to your Tableau Server once and you’ll be able to use it in any number of dashboard hosted on that server. To use it, insert a Web Page component to your dashboard and point the URL to the Web Data Connector. The solution only works when the dashboard is published to the Tableau Server and accessed through a browser. By default the counter will count down from 10 seconds then calls the refreshDataAsync API call to reload the data behind the dashboard before starting a new count down (Like how Russell did few years back). The counter can be customized (seconds, colors, size, etc.) in a user-friendly way with the use of parameters defined in Tableau Desktop. All this is achieved without the need to embed the Tableau Dashboard into any other web page, which is the beauty of this solution.

How many days until the Tableau On Tour Conferences?

How many days until the Tableau On Tour Conferences?

The usual solution

After a quick Google search I came to know that this requirement often comes up (don’t blame me that I needed Google for this, I’m coming from a Spotfire background, barely used Tableau before). Most solutions which are currently out there are floating around the following approach:

  • have a HTML page
  • embed a Tableau dashboard into that HTML page
  • use the refreshDataAsync() API call combined with a setInterval to do this on a regular basis

The main downside of this is that you need an extra HTML page, a web server which serves this page, someone familiar with HTML/JavaScript to set this up for all dashboards where it’s required, so all in all it is not really user-friendly and flexible.

A more user-friendly solution

If you are a regular reader of the DataBoss blog, you might already know what the secret ingredient is going to be: Tamás’ article from last year covers how the JavaScript API can be used with the help of a web data connectors and without embedding. Later Zen Master Chris DeMartini used this to embed fancy D3 charts or Bryant who played with the default data filters. If you are not familiar with the ‘magic’ head over here first to get caught up – I’ll wait for you right here.

Now that we are on the same page, let’s see the approach to tackle the problem:

  1. develop a standalone HTML file which has a visually appealing counter
  2. deploy this as a web data connector to your Tableau Server
  3. at this point you can add a Web Page component to your dashboard with its link pointing to the Web Data Connector
  4. the counter can be further customized to best fit your style

The good news is that I’ve already done the hard work for you for step 1, while step 2 you’ll only need to do once for each Tableau Server you wish to this on. Step 3 is the easiest step by far and can be done with the same ease for any number of dashboards. Last but not least, step 4 is completely optional the default values are working just fine but if you want to customize the counter you can do it.

How to install it

Grab the HTML file from here (view source here just so you can ensure I don’t have anything fishy in it) and copy it to a temporary location on your Tableau server. This file will need to be deployed as a web data connector. When logged in to your Tableau Server with remote desktop, you’ll need a command line prompt to run the import_webdataconnector command. In Tableau 10.x there are two ways to enable a Web Data Connector, but we’ll need to use the import method for this solution to work. That is because we are using the JavaScript API so we need the Web Data Connector to be running on the same host where Tableau Dashboard is served from, otherwise it would fail. For further details about Web Data Connectors check out the official documentation.

Long story short, here is how I imported my shiny connector:

You can ignore the warning about the deprecated command, it’s not going away any time soon. Note down the URL which was returned from the command. If you normally access the Tableau Server with a DNS address make sure to update the URL accordingly. Unless you use a custom port for running your Tableau Server (ie. anything apart from :80 for http:// and :443 for https://) you can leave out the port.

Once you have the final URL feel free to test it in any browser. You should see the green counter with the default 10 seconds label on it and while it’s not doing anything that’s normal at this point. If you see the green circle then you are good to proceed. The Tableau Dashboard is going to be the one which will start it once it is loaded. If you are familiar with your browser’s Developer Tools you can manually start it with the countdown.start() command in the console, but that’s not required, you’ll see it in action in just a second.

How to use it

Okay, now that the technical prerequisites are done the rest of this guide are going to be much simpler I promise. At this point, you should have the direct URL of the Web Data Connector which you imported in the previous section.

Open up Tableau Desktop and either open an existing Workbook or create a new one with any data in it, it doesn’t really matter. Go to Dashboard view and add a new Web Page object with the URL pointing to the Web Data Connector. That’s it, I told you it’s going to be really simple. If you publish your Dashboard at this point, you’ll have the counter working with its default values (10 seconds timeout, 30px radius, green color palette, etc.) and if you are happy with these defaults then you can call it a day. If not, read along.

How to customize it

The beauty in the Tableau JavaScript API is that you can read the values of parameters or even subscribe to events when they are changing. Utilizing the power of this allows us to customize the counter in a user-friendly way without the need to dig into the HTML/JavaScript code of the Web Data Connector. The JavaScript API only works when the Tableau Dashboard is published to the web so unfortunately you won’t see the effect of the parameters in Tableau Desktop.

Without further ado, this is the list of parameters you can use to customize your counter:

  • autoRefresh_seconds: The number of seconds to count down from
    • Data type: integer
    • Default value: 10
  • autoRefresh_radius: The radius of the arc in pixels
    • Data type: Float
    • Default value: 30
  • autoRefresh_direction: The direction of the count down, clockwise (cw) or counterclockwise (ccw)
    • Data type: String
    • Default value: cw
  • autoRefresh_smooth: Should the timer be smooth or stepping once every second
    • Data type: Boolean
    • Default value: True
  • autoRefresh_fontSize: The font size, dynamically calculated if omitted (radius / 1.2)
    • Data type: Float
    • Default value: undefined, calculated from radius, eg. 30 / 1.2 = 25
  • autoRefresh_fontWeight: The font weight of the label
    • Data type: Integer
    • Default value: 700
  • autoRefresh_fontColor: The font color
    • Data type: String
    • Default value: #ffffff
  • autoRefresh_fontFamily: The font family
    • Data type: String
    • Default value: Sans-serif
  • autoRefresh_label: The label to display below the counter. Two labels are expected separated with a comma, one singular label for the second (ie. second or sec) and a plural label for anything more than that (ie. seconds or secs). If left blank or only a single label given no labels are going to be displayed.
    • Data type: String
    • Default value: second,seconds
  • autoRefresh_strokeWidth: The stroke width, dynamically calculated if omitted (radius / 4)
    • Data type: Float
    • Default value: undefined, calculated from radius, eg. 30 / 4 = 7.5
  • autoRefresh_strokeStyle: The color of the stroke
    • Data type: String
    • Default value: #477050
  • autoRefresh_fillStyle: The fill color
    • Data type: String
    • Default value: #8ac575

For any color related parameters, use the HEX color code starting with ‘#’ – there are dozens of color pickers online, search for one if in doubt.

So the flow of customizing the counter is as follows:

  1. Create a parameter in your Tableau Workbook for the one your are not happy with the default value, eg. autoRefresh_radius.
  2. Select the data type as denoted above and enter the new value you wish to use
  3. You have the option to either hide or display the parameter control in the dashboard. If displayed users of the Dashboard are going to be able to change the parameters on the fly and see the counter picking up the new settings instantly. This could come handy for playing with it until you find the options you want to stick with
  4. Note that in Tableau Desktop the counter will not pick up any of these parameters but when published to the web it will

Just to recap, only for the options you wish to override you’d need to create a parameter for, with the rest you don’t need to bother.

Technical tidbits

For the sake of completeness I would like to share a couple of things about how it’s all wired up under the hood, so you’d have a better understanding if you’d need to dig into the code.

When the Dashboard is launched with the Web Data Connector in it, the  <body onload="appApi.initAutoRefresh();"> (line #320) will be the one triggering the whole event chain, that function is defined starting from line #301. The countdown._drawCountdownShape  and countdown._drawCountdownLabel are only there so that in Tableau Desktop you’ll see at least something when the component is first added to the Dashboard, those lines can be safely removed if you are not worried about that.

Few lines below that, the getTableau function is what does the magic for us, so we can communicate with the JavaScript API of Tableau even within the Web Data Connector. Since our code is inside the Tableau’s own code within an iFrame, using the  parent JavaScript function, we can refer to the parent of our iFrame so using the parent.parent.tableau  (line #224) we can grab the object of the Tableau JavaScript API.

The initAutoRefresh()  does two more things apart from all this: subscribes to the event of parameter value changes ( onParamChange) and reads the current list of parameters ( getParameters). They both eventually will reach the processParam function which handles all parameters. Once all parameters are processed for the first time the countdown will be started at line #251.

One more interesting bit is at line #325. The onComplete() function of the countdown object is what defines what to do when the counter ticks. Ultimately what we want is to start a new countdown. The countdown.start() would simply do just that, but the problem with that is that it will start the new counter even before our Dashboard has finished reloading the data. That wouldn’t be too nice, imagine if you have a dashboard taking 8 seconds for example to refresh and you set the counter to 10 seconds – the Tableau Server would only have a 2 second break. Here is what I wanted instead: reload the data once the counter ticks -> wait for the Dashboard to finish reloading -> star a new counter. You would think (or hope at least) that the refreshDataAsync()  function of the JavaScript API would tell us when the refresh is done, but unfortunately it doesn’t (Tableau guys, if you are reading this, please make this function return a Promise like some other async function calls – cheers!).

How I ended up tackling this is that I used the MutationObserver so I can detect DOM changes. This MutationObserver is supported from IE11 and all other modern browser – Tableau 10.x also only supports IE11 and above from Microsoft’s browser so you should be good to go. If you need this solution for older Tableau versions and therefore need support for IE10 and earlier, you’ll need to tinker what this bit (or you might as well upgrade your Tableau Server to a newer version, right?). The MutationObserver will look for the loadingSpinner  element – as its name suggests that’s the spinner what you see when the dashboard is loading. Once it’s done, it will start the next countdown.

Got questions?

Feel free to ask

Norbert Ledenyi

Norbert Ledenyi

Have most of my BI experience with Tibco Spotfire, but interested to learn more about other BI tools and data visualization platforms too. When I'm not building new reports I also quite enjoy getting my hands dirty and muck around with the back-end to understand how things work.
Norbert Ledenyi

Latest posts by Norbert Ledenyi (see all)

  • Jason Mack

    Thanks for sharing this interesting technique. Curious if you guys have explored the security implications of the ‘trick’ required to get this to work. Does installing those items on the Tableau server allow any user to execute arbitrary JS code?

    • Only the administrator can import these plugins with tabadmin commands. It’s secure, however, your administrator must check every to be installed plugins. When they are uploaded it is just a static html page, it can do only what is coded in it.

  • JG

    This is awesome!!

  • Veronica Simoes


  • gilibi

    It seems awesome!
    Is there a way to implement such a solution in Tableau Online as well?

    • You cannot do this with Online without using an external Portal and JS API. However, if you embed your workbook somewhere else you can definitely leverage this

  • Alex Lokhov

    This amazing post inspired me to build an ‘Export to Excel’ plugin for Tableau Server, I used the same technique to avoid embedding. You can check it here:

    • Sounds great, thanks for sharing. We built something similar except that we export the “crosstab” data, not the underlying/summary data. Our users just love it 🙂

      Also, we inject the download button directly to the toolbar, not to the viz:

      • Paul Hardman

        Hi Tamas

        Did you ever publish how you did the “crosstab” export without using custom views?

      • Balaji Asokan

        Hi Tamas,
        This feature sounds very interesting. Can you please guide on how you have implemented this?


    • Tyler

      This is really great, thank you Alex! Do you know if it Is it possible to have it export the detailed/full data instead of the just the summarized data?

      • Huihan Li

        Great! Thanks for sharing. I’m wondering if the ‘Export to Excel’ plug in will work for filters or not?

  • Huihan Li

    Hi Tamas, great work! Thanks for sharing. But I come across a problem when I published the workbook with web data connector. It didn’t show up in the tableau server with the error message “url must start with https://“. My url is what the server returns to me, it’s like http://myserver:80/webdataconnectors/counter.html. Do you know what’s going wrong? Thank you.

  • Arun Gutta

    Hi Norbert
    This is really awesome we are using the Refresh circle, it works great, there is a problem though we have 3 Action URLs on the Dashboard how to handle those with the Auto Refresh Circle?

  • m sagar kumar

    Hi Norbert,

    Thanks for the solution, this seems great. But I am facing a challenge, when I am moving to other dashboard/tab and then coming back, the timer is getting reset. Please let me know if is there any way of stopping it from getting reset.


    • Yes, this is how it works now. If you want to have a more consistent countdown that persist across tab selections you can use the current time’s second part. Like the refresh should happen every time the second part modulo 15 equals to 0. Hope this hleps

  • Pooja Agarwal

    Hi Norbert,

    Really a great approach, worked well for me.

    The only difficulty I have is, once the count reaches to zero, the next countdown is not starting by itself. I need to reload the page and only then the countdown is starting.

    I might be missing something, please help me with this.


    • It should be restarted. Can you paste the logs/erros from your Chrome Developer console?

    • Tom Cook

      I had the same issue. It would work in Firefox but IE, Chrome, and Safari would only refresh once. I got it working by moving the countdown.start(); to after the refresh and commenting out the mutation observer stufd. The console showed AutoRefresh init auto-refresh.html:302
      AutoRefresh parameter received: autoRefresh_seconds with the value of 5, type: number auto-refresh.html:255

  • Adam Fessl

    Hi Norbert,

    This approach seems good, I would like to try it – could you help me with implementation?
    Following the instructions I get Javascript Error on final dashboard „Cannot read property ‘getVizs’ of undefined“ that is caused by undefined VizManager on getTableau() function:

    getCurrentViz = function() {
    return getTableau().VizManager.getVizs()[0];

    I Use Tableau Server 10.4 in local network. Dashboard is live-connected to DB, so password to DB is needed for the first time.

    „Refresher“ data connector is added to dashboard via static IP:

    Client & Server running WIN10.

    Thanks for advice,

  • John Forlow

    Hi —
    This looks very helpful.
    I have loaded the object onto my server and have placed it into one of my Tableau workbooks.
    I can get the object onto my dashboard, but the counter is not moving.
    Is there something that I missed?

    Ant help would be appreciated.

  • daryl cox

    This is amazing and exactly what i needed.
    ideally i would like to set my dashboard to refresh every 15 minutes. obviously i can set the refresh seconds to 900 and everything works fine.
    is there a simple way to get the counter to countdown from 15 as minutes rather than the seconds value.
    i would like to keep the stroke using the seconds as i think this will look better and smoother



  • daryl cox

    Also noticed that when i view the report in tableau server this all works perfectly, however most of my clients access the report from publishing the share URL and this doesnt seem to work.

    has anyone managed to get this working at all



  • daryl cox

    just looked in the chrome console and this is the error being thrown. Any ideas please help



    • What versions of Tableau Server is this?

      • daryl cox

        its 10.5

        • daryl cox

          doing a bit more investigation it looks like i need to add a couple of elements to the html file but i am unsure where to add them.

          i found info here:


          do you know where i can add these to the file. i think its something to do with this bit

          • Seems like a new security setting in 10.5. I think it’s enough to move the inline javascript contents to a separate file (in the same webdataconnector directory). I’ll try to reproduce this on my end

          • daryl cox

            Thanks for your help, its much appreciated, let me know if there is anything you need. this will be massive if you can fix this



          • Please give a try with this one

          • Jamie Stooke

            Have you ever tried to get this working when the dash is viewed via the Tableau iOS app? seems to just render the timer but doesn’t start counting down. Any help would be much appreciated!

          • actually I did not tried – simply I do not have an iOS device (I’m and android man)

          • Jamie Stooke

            Hi Tamas, no worries. I looked a little deeper and it seems :embed views and views rendered in the iOS app don’t appear to have VizManager available in parent.parent.tableau. I was specifically after the refresh functionality and found that; for embedded views does the same as parent.parent.tableau.VizManager.getVizs()[0].refreshDataAsync(); for non embedded views.

            Still not sure how i’m going to get the countdown timer working on embedded views as i’ve not found the equivalent for getParameterAsync yet. Have you done any work with vqlweb.js?

          • Paul Rowles

            Hi Tamas

            Just wondering if you had got any further with this? It’s a shame that this approach doesn’t work in 10.5!

          • it works flawlessly with 10.5

            I will drop you a private note, if you want we can have a look on it together

          • hmm, OK, on an another server I was able to reproduce it. looking into it

          • I fixed it here : please give a try – you need two new javascripts as well (need to import separately or host externally )

          • Paul Rowles

            Thank you so much for doing this Tamas! Can I ask how to import the javascripts? I’m pretty new to this aspect of Tableau


  • San

    Hi I have implemented in the same way but it is refreshing only one time and after that countdown is static. Please help me

    • Oliver Rappold

      Same for me. Tamas, any idea why that is the case?

      • did you try this version?

        what is your tableau version and what is the error in chome console if any

        • Oliver Rappold

          Works now, maybe worth to be mentioned that I used the following directory to leverage Tableau tomcat webserver: C:Program FilesTableauTableau Serverpackageswgserver.20182.18.0926.2120publicdesktop

          • prasetya wibowo

            Hi Oliver, could you please explain more detail about your step? I tried to figure it out, but still failed to apply. Please help. Thank you

  • Julian

    Hi Norbert, this works great! How would I change from seconds to minutes instead? I would like to use it to refresh my dashboard every 30 minutes. Thank you very much in advance.

  • Jamie Stooke

    Have you ever tried to get this working when the dash is viewed via the Tableau iOS app? seems to just render the timer but doesn’t start counting down. Any help would be much appreciated!

  • MK

    Can anyone please explain how to enable this with new way of TSM server command line ?? we have Tableau Server v 2018.3 with TSM, so no tabadmin exist !!

    also when I check the corresponding TSM command for this on Tableau site , I found the following:

    tsm data-access web-data-connectors add –name ‘WTA WDC’ –url –secondary*

    and I’m wondering which values I can use for –url and –secondry ??

  • Yuri

    Will it work if there is no internet connection on Tableau Server machine?
    I see in source code that plugin requires some lib from googleapi.
    How to solve this?

    • You can download all the 3rd party libraries to on-premise. You can even host in the same directory as the wdc

      • Yuri

        Thank a lot for Your reply.
        Now it is working on Tableau Server. But I need to embed my dashboard into another site, and when I try simply to access in browser my dashboard in the embed view using the link received with “Share link” option in Tableau Server, i.e. when trying to access dashboard with embed=y option, the counter doesn’t work and web-browser console throws the following exceptions:

        Seems that parent.parent.tableau in getTableau() function returns something different from the case when embed=n (with embed=n everything works fine, but in this case user see Tableau Server toolbar, can access another reports, which is not too good).

        Kindly ask you for advise.

        Thank you

Related items

/ You may check this items as well

Scaling Tableau Image

Scaling out Tableau Extracts – Building a distributed, multi-node MPP Hyper Cluster

I was casually sitting at my desk writing my first...

Read more
Pasted image at 2018_01_09 04_59 PM

Python Experiments in Tableau 1. – Add live currency conversion to Tableau Dashboards using TabPy

I was casually sitting at my desk writing my first...

Read more
Tableau Docker

HOWTO: Tableau Server Linux in Docker Container

I was casually sitting at my desk writing my first...

Read more