Limiting Concurrent Tableau Sessions

The concept of selling for “concurrent users” comes up with relative frequency at Tableau. I’m not in any position to speak about licensing models, but if you are doing single sign-on to your Tableau Server, it’s very possible to implement a concurrency limiter.

The Tableau Server Repository has a view called _sessions, which only shows current active sessions. Prior to your SSO process, you can build a process that checks the _sessions view to see if there are already more active sessions than you want to allow.

My suggested query is the following:

SELECT s.site_id, t.url_namespace, COUNT(s.user_id)
FROM _sessions s
JOIN _sites t ON s.site_id = t.id
GROUP BY s.site_id, t.url_namespace


url_namespace from the _sites view gives you the identifier for a given Site. If you are using Sites, you need this to log in any way (This is called “site_content_url” in the REST API). All of the useful views in the Repository are listed in the excellent Data Dictionary.

Now, because concurrency in Tableau is really more about interactivity than time sitting, you’ll want to drastically shorten the session timeout from the default of 240 minutes. I’d suggest something like 5 so you aren’t locking people out when there is plenty of server capacity.

Also, the _sessions view contains the session_id field which can be used to programmatically end any session using the REST API’s sign out method. Per Russell Christopher: If you pass the session_id in the header like “X-Tableau-Auth: session_id“, it will end that session.

Using Initial SQL to Pass Usernames to Stored Procedures or Views in SQL Server

Tableau 9.3 brings a wonderful new feature called Initial SQL with Parameters which allows you to declare a specific set of SQL commands to be run before any queries within a particular Tableau Server user’s session. One of the initial use cases is Oracle VPD. It can also be used in Microsoft SQL Server with a single technique to solve two issues:

  1. Passing the Tableau Username to a Stored Procedure (previously only possible using the JavaScript API )
  2. How to use the WHERE Method of row level security (see the Row Level Security post for full explanation), when the usernames you need for data security are not users in the database. If the usernames are users in the database on SQL Server, you can use Impersonate User in SQL Server as per the section in this post titled Recommendation: Use the JOIN Method unless the WHERE Method is “easy”. That is to say, this technique is only necessary when the usernames and entitlements exist only in the database tables, and not as part of the database security model.


Managing Published Data Sources and Extracts

The Thinker, Rodin

The best analogy I’ve come up with that making a Tableau great data source is like making a great bronze sculpture. You make the original model that you keep for yourself in your workshop and then you cast new statues each time the outside world needs one. This process allows you make changes to the original model or even make a new model without replacing the existing statues (until necessary).

When used correctly, Data Sources, Extracts, and Tableau Data Server facilitate quick access to data with minimal effort. However, using the correct process and order can save tremendous amounts of time on initial setup and any subsequent changes. A fully thought out process will look something like this:

data source process


Referential Integrity, Join Culling, and Performance

Unlike some traditional BI tools, Tableau dynamically writes the simplest query it can based on what the user drags and drops into the view, versus specifying a different unique optimized query per view. It also uses simple queries that take into account the full JOIN structure like (simplified pseudo-SQL here):

TOP 1 FROM (SELECT fields FROM table t1 JOIN t2 JOIN t3 JOIN t4) t0

to pull metadata information.

This strategy tends to work well for many of the systems Tableau runs on top of, but occasionally runs into trouble if the RDBMS’s query optimizer doesn’t cull out unnecessary JOINS before trying to work out the query. I’d say particularly for systems intended to be DWs the issue does arise (Redshift performance, for example, can be immensely affected if JOINs are not culled out, particularly when users try and include every possible table in the schema).

Join Culling and Referential Integrity


Tableau does have a feature called Join Culling which will remove unnecessary JOINs from any query, but it only works under the following conditions:


Disabling Browser and Apache Caching to See Your Changes to Tableau Server

This post isn’t about viz caching, but rather about disabling the caching in the browser and in Apache so that you can see your changes as you modify CSS or other files when customizing vizqlserver and vizportal.

Browser Cache

Browser cache is always an issue when trying to see the latest version. The best method for rapid testing I’ve found is Google Chrome’s Developer Tools. Under the Network tab, there is a wonderful “Disable cache” check box. Regardless of what tab you are looking at, once this check box is clicked, as long as the Developer Tools toolbar is up (no matter how minimized), every page refresh will get a new version from the web server.

Apache Cache

That’s not enough though, because Tableau Server also has caching on at the Apache web server level. All of this is controlled in the standard httpd.conf file, which is located at:

C:\ProgramData\Tableau\Tableau Server\data\tabsvc\config\httpd.conf

Even better, this change persists through Tableau Server installations the best I can tell.

Go through the .conf file and find anywhere with ‘ExpiresDefault’ set to “access plus 1 year” and change it to “access plus 2 seconds”. Then restart Tableau Server. Now Apache won’t be serving up a cached version to the browser after 2 seconds.

Later you can change it to a longer time period, although I don’t know that 1 year is ever necessary.

Update: Recently, one of the excellent support engineers at Tableau let me in on this tip:

“The httpd.conf gets updated whenever configuration is saved or tabadmin config is ran. You would need to update the template if you want it to persist.

Tableau Server\10.0\templates\httpd.conf.templ (primary or single-node)

Tableau Server\worker\templates\httpd.conf.templ (worker)”

So if you want persistent changes, you’ll need to update the template (and that of course will be overwritten when you make your next upgrade. Such is the life of hacks).

gzip files

One last hurdle to making changes is that there are .gz versions of each HTML/CSS/JS file which the Apache server is configured to be used if they exist instead of the real file. If you want to test a change, you need to remove the .gz file somehow (the easiest way is to add ‘.original’ to the end of the file after .gz) so that the .html/.css file is being used. You can save your edited HTML/CSS file later to a .gz so it is served up even more quickly.

Embedding Web Edit in an iframe

Update 2019-12-31: A new and improved method, thanks to Madhav Kannan

While the below post still works, Tableau’s Madhav Kannan has developed a newer technique that doesn’t require any additional files be added or hosted on the Tableau Server. Highly recommended that you look to his solution first, and then if you need the slight additional features of the method below, consider if it is worth the effort and maintenance.

Update 2017-04-17: Big hat-tip to Tableau’s Santiago Sanchez, who gave the heads up that an update was needed for Tableau 10.2. If you’ve upgraded and things aren’t working, please download the new versions available on GitHub. There are other updates as well to handle the full range of behaviors of the web edit screen.

Update 2018-11-02: Second hat-tip to Tableau’s Ron Dugger who found where you can put this file in 2018.2 and later versions of Tableau Server. Things move, we find them!

It’s pretty simple to embed a Tableau viz into a web page. You can do it directly with an iframe, use the simple JavaScript API embed available with the “Share” button, or do the full JavaScript API embed. However, when you embed a viz, when the Web Edit button is enabled, the default behavior is for a second window to open up with the Web Edit view, which looks similar to Tableau Desktop (another post about cleaning up general ‘theme’ will be forthcoming).

The main issues with this popup window are:

  1. The URL bar in a browser will show the Tableau Server location rather than your web application
  2. The separate window can break the intended UX flow
  3. When the user is Done, the window closes, and it returns to the original page with the embedded viz. But nothing in that viz changes — and since most Web Edit will result in a Save As, the user is now looking at an unchanged viz that is no longer even the correct workbook.

Note: Everything that follows is completely unsupported by Tableau Support.