Tableau command line Batch PDF generator
If you need to generate a series of PDF files based on the same Tableau Dashboard, but with each PDF using different values to filter the data displayed, you could end up a bit frustrated as out of the box this would mean manually selecting each filter value, then selecting export as a PDF. Fine for a few values, but not a particularly enjoyable experience as the number of filter values increases.
The Batch PDF generator is a java executable that lets you configure and automate this process in a repeatable fashion. It’s functionality breaks down into two parts, firstly you create a Tableau worksheet that will contain the values you want to iterate over and pass as filters to your Dashboard. Secondly you create a dashboard that you want to use to generate PDF files, based on the filter values you got from step 1.
There are probably multiple examples creating this functionality available, some using TABCMD, others using Tableau’s REST API, written in various programming languages. In fact I am using some of the concepts found in Alexis Guinebertiere blog “Email alerts with Tableau”, written in Ruby.
This project uses Tableau REST API which has some advantages over TABCMD, the main ones being:
- You do not have to install TABCMD on the PC you are running the code on (which can only be Windows)
- TABCMD has some subtle nuances when running multiple jobs at the same time, where you need to write your code to log in for each separate request you want to make, drastically slowing down the process. This is not an issue for the REST API, where we only log in to the Tableau Server at the start of the process and then use a returned token for subsequent requests. Using Java means we can easily add multithreading, so that you can submit simultaneous PDF generation requests
- See Tableau Server REST API help to view additional functionality
Setup
Tableau
The filter values worksheet and PDF dashboard need to be published to a Tableau Server (online or an on-premise server).
The filter values worksheet can be the in the same workbook as the dashboard, or in separate workbook
User Permissions on published workbooks
You need to provide Tableau Server login credentials as part of a properties file so that the program can interact with Tableau Server. This login needs to have some minimum permissions on the workbook(s) you are using.
The login user does not need any project permissions

To retrieve the values to iterate over the login user needs
- Download summary data
- View
To generate the PDF the login user needs
- View
- Filter
- Download Image/PDF
If the values to iterate over and the Dashboard to download are in the same workbook (or Project) the permissions at a minimum would look like:

Environment
JRE (Java Runtime)
You will need Java 8 JRE, or higher, installed on your PC to run the program
(see https://www.oracle.com/java/technologies/javase-jre8-downloads.html)
Download and save the compiled code located on github.
(see https://github.com/Jeremy-Weatherall/PDF_RestAPI/tree/main/Compiled%20Code)
The download has four parts
- restAPIPDF.jar is the compiled java code
- properties.prop is the file where you define how to log on to the Tableau Server, the name of the filter values worksheet and PDF Dashboard, and where to store the generated PDF files.
- runme.bat gives an example of how to run the PDF program, where you choose which properties file to use (each property files could define different PDFs to generate and at run time you choose which one you want to use)
- Test View.twbx is a packaged workbook copy of the workbook created in the End to End walkthrough detailed later in this post

Note: you can download the source code. The best I can claim is that I dabble in coding, and that is probably a bit of a reach. The good news is that you can amend the code to suit your own needs. This source code is an Eclipse Java Maven Project. https://github.com/Jeremy-Weatherall/PDF_RestAPI/tree/main/cmdLine_RESTAPI_PDF
Considerations
If you have read this far you should be thinking about limitations and could this really meet your needs! As I don’t know what you want to do, not one I can answer, but I’ll address a limitation and answer a few of my own soft ball questions!
For ease of coding only one column in your datasource can be used as a filter, you define this column in the properties file. This works great if for example you want to generate a PDF for each student by iterating over the students name, but if you want to pass in student name and term, values from two columns in your data source, not so great! In cases like this you need to do a little work. In Tableau create a new Calculated Field that concatenates the columns you want to use for filter values so that they are now in one column, and use this as your filter column, then populate your filter worksheet using this new column

How thoroughly has the code been tested?
It worked for the use cases I tested, but no guarantees, the code is as is, though let me know if you have problems and I’ll do my best to respond. This code is my own personal work and is not provided or supported by Tableau.
Have thoroughly tested are different types of filter values?
- Filter values with spaces and non ASCII values should work, looking at you Anthony O’Donnell and also Barry Französisch!
- Filter values with commas in are supported i.e. Adam Bellavance, Region, Central
- Filter column names with spaces are supported
How fast and how many reports can I create?
The generation speed is dependent on how fast your Tableau Dashboard loads on your server, and if you are running this against your own on-premise Tableau Server, what work load the server is currently under. I have generated 2,500 reports against a Tableau Online dashboard, running 10 simultaneous PDF requests, this ran without problems.
Note: you can configure how many concurrent requests you make to the server, from 1-10 simultaneous PDF requests.
Is any part of the setup a bit tricky?
Great question, and yes, there is one area that can be a little bit confusing, and this is around how we locate a workbook, worksheet and dashboard using the REST API. Worksheet and dashboard names are only guaranteed to be unique for a workbook, and workbook names are only guaranteed to be unique for a project. To ensure we can locate the correct content we use the workbook, and view (or dashboard) name as they appear in the URL when viewing content in the browser. Easy to use once you know the format required.
Let’s look at an example: There are two workbooks with the same name of Test View(1), saved in different projects (2), so how do I define which one to use in my properties file?

Comparing how the two duplicate workbook names appear in the browser, the workbook created and saved last has a lot of numbers appended to it’s name in the URL, this is referred to as the ContentURL, and you need to define this value in the properties file to allow the REST API to locate the correct workbook.

How the lower view would appear in the properties file?
https://../#/site/jeremyonline/views/TestView_16129846298070/CustomerandYear_1?:iid=2
Note: You can ignore URL until after /views/, and then also ignore any content starting at ?, in this case ?:iid=2
- csv.url.workbook.name=TestView_16129846298070
- csv.url.view=CustomerandYear_1
End to End Walkthrough
Using a Tableau Online account and superstore data we will create a worksheet that contains the values we want to use as filter values, and pass these to the dashboard that we want to generate the PDFs for.
Note: the completed workbook is part of the compiled code download.
Create the view that contains the filter values to iterate over
- Name the worksheet ‘Filter values’, you can use whatever name makes sense to you
- Create a new Calculated column that concatenates two columns together, as the PDF Generator only accepts one filter column, if you plan to filter on one column, skip this
- Populate the worksheet with values
- Note: you could optionally create a filter on this worksheet to restrict the values being returned, using some criteria i.e. students with failing grades

Create the dashboard to generate PDFs for
This dashboard is going to have two charts, a Sales for each State and Sales by Year.
Create the Sales for each State
Add a title telling us who the PDF is for, to do this we add our new Filter Column to Details (1) and include this in our Title for the Map (2 + 3)
Note: we are using the title on this worksheet to display information about the filter value as it is not something we can add to the dashboard (the dashboard is a container, and does “know” about the data populating the worksheets it contains). You would amend the title for the worksheet you want to appear at the top of the dashboard

Create the Annual Sales worksheet

Create the Dashboard
Set the size of the Dashboard to the page size of your PDF. We will also set the page size and orientation in the properties file, but having the two sizes match can prevent unexpected resizing.

In the dashboard, the map below is showing values based on the detail of our new Filter column, which doesn’t match what our annual sales are currently showing, but when we pass in filter values this will all work. Once a filter has been applied, the All in the title will reflect the passed in filter value. (See PDF example for generated report format at end of blog)
Note: we have not used our new filter column as a filter, and it is not even on the Annual Sales worksheet, but the REST API will apply the filter values to both worksheets at run time.

Now save the workbook to Tableau Server and use the browser URL to populate the properties file.

Properties file settings
Using the URL we get a lot of information that we will use in the properties file, csv.url.* tells us where to locate the filter values to iterate over.
- csv.url.workbook.name=TestView_16134922006850
- csv.url.view=Filtervalues
- server.url=https://us-east-1.online.tableau.com
- server.site=jeremyonline
Other values we need to put in the properties file from the workbook
- Workbook that contains the Dashboard we want to use for PDFs, this can be in the same workbook that we used to get filter values (as per this use case), or a different workbook
- pdf.url.workbook.name=TestView_16134922006850
- Name of the dashboard we want to use
- pdf.url.view=Dashboard1
- Name of the column that we are passing in filter values for, in this case it is the same as the column we used to generate filter values in our view
- pdf.Filter.Column=Fancy New Filter Values Column

Other property settings
- Location to save the PDF files, this folder needs to exist
- file.Output=C:\\Temp\\pdfOutput\\
- Optionally define a location and name for your log file (folders need to exist), if this is not defined the log file is saved where you save the downloaded jar file
- logFile=C:\\Temp\\pdfOutput\\PDFlog.log
- Tableau Server user name and password that allows the code to log on to Tableau Server, these credentials need permissions on the saved workbook
- login.user=
- login.password=
- Note: if you are hosting Tableau Server on Prem (v2019.4 and above) you can generate a Personal Access Token and use this for your credentials
- From our help: Personal access tokens provide Tableau Server users the ability to create long-lived authentication tokens. The tokens allow users to run automation with Tableau REST APIs without requiring hard-coded credentials or interactive login
- PDF page options
- The value can be Portrait or Landscape. If this parameter is not present the page orientation will default to Portrait.
- page.layout=landscape
- The value can be: A3, A4, A5, B5, Executive, Folio, Ledger, Legal, Letter, Note, Quarto, or Tabloid. If this parameter is not present the page type will default to Legal.
- page.size=letter
- The value can be Portrait or Landscape. If this parameter is not present the page orientation will default to Portrait.
- Number of concurrent PDF requests made to Tableau Server, default 1, max 10
- concurrent.requests=10
All the values in a property file!

How to run
There are multiple ways to run an excutable, we will show a couple of options here.
CMD line
Open CMD and CD directory to the location where you have saved the four files you downloaded from github

Make sure you have updated the properties file with your information as shown above
Now enter the following text to start the generation
java -cp “*” com.tableau.cmdline.restapi.BatchPDF properties.prop

- Only change the green text if you need to specify the path to your java executable, by default it should be added to your path and you will not need to do this.
- The location and name of the properties file you want to use. There is no location specified in this example, telling the code to look in the same folder as the jar file
Bat File

Modify the bat file to locate the folder where you saved the compiled code from github
Note:
- You can use a scheduler to run bat file
- I haven’t been able to test the bat file syntax as bat files are not permitted on our laptops.
Example output
PDF Output
Note: the file name is based on the passed in filter value

I am happy to answer questions if you encounter any problems setting this up. I just want to emphasize again that this is my own work and not supported by Tableau in any way.
Diane
Jeremy, thank you so much for sharing this. It is going to be very helpful for us. I do have one question. I tried applying this to a dashboard that contains six different charts. The filter is only being applied to the first two. How can I get it to apply the filter to all of the charts on the dashboard?
Jeremy Weatherall
Hi Diane,
Happy to help trouble shoot this with you. I’ll start with easy to fix areas first. If we cannot find a solution that way I’ll put on my Tableau employee hat and we can schedule a screen share, it that is something you would be OK with.
Do your charts all use the same data source? If not, does the column name where the filter works match the column name in the charts where the filter is not being applied? This approach should not care about data sources (though I did not test this, so I will confirm), it should only care about the column name matching the passed in filter name.
Best wishes
Jeremy
Diane
Yes, they all use the same three data sources. The pages that are working have the filter value field is on the primary data source. The other pages, the data source with the filter value is the secondary data source. Do I need to have a field with the filter value in all of my data sources?
Jeremy Weatherall
Hi Diane,
Each data source needs to a have a column with the same name as the filter column name defined in pdf.Filter.Column. In the example above we created a calculated field called “Fancy New Filter Values Column” for one datasource. If we added new data sources to the dashboard and we wanted to filter the new data sources with passed in filter values, then you would create a new calculated field in the new data sources called “Fancy New Filter Values Column” and use this to refence the values in the new data source that will match the passed in filter values.
Let me know if this does not make sense.
Best wishes
Jeremy
Bala Vikas
Can this be done on Tableau Online? Or, need a Tableau Server license?
Jeremy Weatherall
Hi Bala,
This will work for Tableau Online as well as Tableau Server.
Best wishes
Jeremy
Bala Vikas
Have you done this in Python? I feel more comfortable with it so might do the Java piece in Python if the code isn’t available.
Jeremy Weatherall
Hi Bala,
I have only written this in Java, but you could replicate the logic of the code and use a python library to make the Tableau Server REST API calls, as opposed to coding this area as well. https://tableauandbehold.com/2019/12/09/tableau_tools-5-0-python-3-for-2020-and-so-much-more/ has created a python library that has encapsulated the REST API calls.
Best wishes
Jeremy
Bala Vikas
Thanks! Have you tried using this with a dashboard parameter action? This is how it is on my dashboard. Would it work?
Bala Vikas
What’s the difference between the Tableau JavaScript API and the Tableau Rest API? Can each one of these be used separately to make batch .PDFs? — extremely rudimentary knowledge of this… feel free to e-mail.