Rest API Beginner

#DDQ2025-01 Generate PDF using Tableau REST API (Beginner)

Learn to automate PDF report generation with Tableau REST API. This beginner-friendly guide covers setting up a Tableau Sandbox, using Personal Access Tokens, and exporting dashboards seamlessly.

C

Cristian Saavedra

Author

2025-01-15T04:32:32
6 min read
preview.png

Welcome to the DataDev Quest Challenge for January 2025! This challenge is designed to learn how to use Tableau REST API, Tableau Server Client, and Tableau Developer Sandbox to generate a PDF from a Workbook published in Tableau Cloud.

Challenge Overview

Objective:

Write a Python Script that uses Download Workbook PDF (REST API) to generate a PDF from Tableau Cloud. Check the challenge at the end of the guide.

Why this challenge?

Many organizations rely on Tableau to generate PDF reports to share critical insights. However, when dealing with a large number of workbooks, manually generating these reports becomes time-consuming and error-prone. Automating this process using Tableau Server Client and REST API not only saves time but also ensures consistency and scalability.

Learning Goals

  • Get your Tableau Developer Sandbox
  • Configure Personal Access Token (PAT)
  • Install Tableau Server Client
  • Connect to your Developer Site using PAT
  • Search a Workbook by Name and Content URL
  • Generate PDF from Workbook

Submission Guidelines

  • Source Code: Publish your project publically in the GitHub profile
  • Add README: Include setup instructions and describe how to run the program.
  • Video of Solution: Include a video of your solution in the README file, which you can publish on YouTube and embed the iframe. Or save the video file in the directory root inside the repository.
  • Comments: Ensure your code is well-commented.
  • Submission: Submit your challenge in the following **forms**

Additional Resources


Getting Started

The first step is to get and set up your Tableau Developer Sandbox. By following my Medium Post, you will get a step-by-step guide to configuring it.

1. In your Tableau Cloud Site, create a Folder with the name DataDevQuest and a subfolder 202501 as follows:

2. Download World as 100 people_by_Paula_Munoz by Paula Muñoz to your machine.

3. Open with Tableau Desktop and Sign In to your site using your full URL, copying and pasting from your browser. The URL will look similar to https://10ax.online.tableau.com/#/site/cristiansaavedradx

If It asks you to enter the URI, copy the text after site/ in the URL, in my example, it is cristiansaavedradx

4. Publish the workbook selecting Only Dashboards in the location DataDevQuest / 202501:

5. Be sure that you have Enabled the Personal Access Token (PAT) and configure your Personal Access Token (PAT). If you need help, follow my Medium Post, where I explain how to get it.

6. Install Tableau Server Client (TSC) in your Python environment. You can check Medium Post for more information.

7. Modify the following example code with your URL, PAT Token, PAT Secret, and Site ID.

CODE
import tableauserverclient as TSC

my_server_url = 'https://10ax.online.tableau.com/'
my_token_name = 'test'
my_token_secret = '+z+Gy5CSSi+VVotuzo44A==:ai5xKL1A6Dfmf6OIstMuiOGhGbvN0MxpS'
my_site_id = 'cristiansaavedradx'

tableau_auth = TSC.PersonalAccessTokenAuth( token_name=my_token_name
                                           ,personal_access_token=my_token_secret
                                           ,site_id=my_site_id)
server = TSC.Server(my_server_url, use_server_version=True)

with server.auth.sign_in_with_personal_access_token(tableau_auth):
    print('[Logged in successfully to {}]'.format(my_server_url))

8. Execute the code, and you will get a Logged in successfully message to your Tableau Cloud Site.

9. Modify the following example code that searches the Paula Munoz Dashboard in your Tableau Cloud Developer Site using the Name and passing RequestOptions. For more information, check Filter and Sort

CODE
import tableauserverclient as TSC

my_server_url = 'https://10ax.online.tableau.com/'
my_token_name = 'test'
my_token_secret = '+z+Gy5CSSi+VVotuzo44A==:ai5xKL1A6Dfmf6OIstMuiOGhGbvN0MxpS'
my_site_id = 'cristiansaavedradx'
my_workbook = "world as 100 people_by_Paula_Munoz"

tableau_auth = TSC.PersonalAccessTokenAuth( token_name=my_token_name
                                           ,personal_access_token=my_token_secret
                                           ,site_id=my_site_id)
server = TSC.Server(my_server_url, use_server_version=True)

with server.auth.sign_in_with_personal_access_token(tableau_auth):
    print('[Logged in successfully to {}]'.format(my_server_url))
    
    req_option = TSC.RequestOptions()
    req_option.filter.add(TSC.Filter(TSC.RequestOptions.Field.Name
                                    ,TSC.RequestOptions.Operator.Equals
                                    ,my_workbook))
 
    workbooks, pagination_item = server.workbooks.get(req_options=req_option)
    if workbooks:
        print(f"=== Workbook ===")
        print(f"Name:{workbooks[0].name}")
        print(f"luid:{workbooks[0].id}")
        print(f"URL:{workbooks[0].webpage_url}")
        print(f"Content URL:{workbooks[0].content_url}")

10. Execute the code, and you will get information like the name, luid, URL, and Content URL. The Content URL is a unique resource that you will see also in the URL when you use the Tableau Web Interface, for example:

https://10ax.online.tableau.com/#/site/cristiansaavedradx/views/worldas100people_by_Paula_Munoz/The_World_as_100_People?:iid=1

11. Modify the following code example to use your PAT and replace the variable pdf_file_name with the path where you want to download the pdf on your machine.

CODE
import tableauserverclient as TSC
import os

my_server_url = 'https://10ax.online.tableau.com/'
my_token_name = 'test'
my_token_secret = '+z+Gy5CSSi+VVotuzo44A==:ai5xKL1A6Dfmf6OIstMuiOGhGbvN0MxpS'
my_site_id = 'cristiansaavedradx'
my_content_url = 'worldas100people_by_Paula_Munoz'
pdf_file_name = f'./01_beginner/{my_content_url}.pdf'

tableau_auth = TSC.PersonalAccessTokenAuth( token_name=my_token_name
                                           ,personal_access_token=my_token_secret
                                           ,site_id=my_site_id)
server = TSC.Server(my_server_url, use_server_version=True)

with server.auth.sign_in_with_personal_access_token(tableau_auth):
    print('[Logged in successfully to {}]'.format(my_server_url))

    req_option = TSC.RequestOptions()
    req_option.filter.add(TSC.Filter(TSC.RequestOptions.Field.ContentUrl
                                    ,TSC.RequestOptions.Operator.Equals
                                    ,my_content_url))

    workbooks, pagination_item = server.workbooks.get(req_options=req_option)
    if workbooks:

        wb = workbooks[0]
        print(f"=== Workbook ===")
        print(f"Name:{wb.name}")
        print(f"luid:{wb.id}")
        print(f"URL:{wb.webpage_url}")
        print(f"View:{wb.content_url}")

        pdf_options = TSC.PDFRequestOptions(page_type='unspecified', orientation='landscape')

        server.workbooks.populate_pdf(wb, pdf_options)

        print(f'Path:{os.getcwd()}')
        with open(pdf_file_name, 'wb') as f:
            f.write(wb.pdf)
            print('[PDF Generated]')

12. Execute the code, and you will learn how to generate a PDF from an existing Tableau Workbook published in Tableau Cloud.

13 Now, we will re-publish the dashboard with all the sheets. Be sure you select Sheets All and Show sheets as tabs and overnight them in the same location:

14. If you come back to your Tableau Cloud Site and refresh, you must see the following:

15. Run the previous code again. Ohh! Something is wrong; the PDF has only one page, and It is not taking the last version.

16. Do the same exercise, but this time publish with a different name, change the variable my_content_url with the new Content URL, and test the code again.

17. Now you are seeing the PDF with 15 pages, as it should happen in the previous step:


Challenge

Your challenge is to fix the code and allow the same code to work when you republish a new dashboard version. Take the last version of the Dashboard and generate the correct PDF. I will publish the solution in the next session!

Happy Coding!

Have you already solved it?

There are more things you can learn from this exercise, like seeing the different PDFRequestOptions like the Page Orientation.

If you want to know more about the DataDev Community, you can see the recorded session at SalesForce Plus


Who am I?

Hey, I forgot to introduce myself. I am Cristian Saavedra Desmoineaux, a Visionary, Tableau Data Dev Ambassador, and co-founder of DataDevQuest. I am passionate about solving data problems and have over 20 years of experience in complex scenarios. You can contact me on LinkedIn.

DataDev Rules!


Special Thanks to Paula Munoz for allowing me to use her Tableau Public Post for this exercise and
Jordan Woods, who helped me many times with questions related to REST API


The Solution

How can I republish a new dashboard version and generate the PDF?

If you try to modify the Tableau Workbook published to Tableau Cloud and run the script, you will notice that the PDF that is downloading is the old version and not the one you expected. The reason is that Tableau has a cache in minutes, and to force it to refresh an often time, you need to change the parameter maxage as it is shown in the PDFRequestOptions class documentation

Using the PDFRequestOption variables is an elegant way to write it. I changed the solution to be easier to read.

        pdf_options = TSC.PDFRequestOptions(page_type=TSC.PDFRequestOptions.PageType.Unspecified
                                           ,orientation=TSC.PDFRequestOptions.Orientation.Landscape, maxage=0)

The solution code:

CODE
import tableauserverclient as TSC
import os

my_server_url = 'https://10ax.online.tableau.com/'
my_token_name = 'test'
my_token_secret = '+z+Gy5CSSi+VVotuzo44A==:ai5xKL1A6Dfmf6OIstMuiOGhGbvN0MxpS'
my_site_id = 'cristiansaavedradx'
my_content_url = 'worldas100people_by_Paula_Munoz'
pdf_file_name = f'./01_beginner/{my_content_url}.pdf'

tableau_auth = TSC.PersonalAccessTokenAuth( token_name=my_token_name
                                           ,personal_access_token=my_token_secret
                                           ,site_id=my_site_id)
server = TSC.Server(my_server_url, use_server_version=True)

with server.auth.sign_in_with_personal_access_token(tableau_auth):
    print('[Logged in successfully to {}]'.format(my_server_url))
    
    req_option = TSC.RequestOptions()
    req_option.filter.add(TSC.Filter(TSC.RequestOptions.Field.ContentUrl
                                    ,TSC.RequestOptions.Operator.Equals
                                    ,my_content_url))
 
    workbooks, pagination_item = server.workbooks.get(req_options=req_option)
    if workbooks:

        wb = workbooks[0]
        print(f"=== Workbook ===")
        print(f"Name:{wb.name}")
        print(f"luid:{wb.id}")
        print(f"URL:{wb.webpage_url}")
        print(f"View:{wb.content_url}")

        pdf_options = TSC.PDFRequestOptions(page_type='unspecified'
                                           ,orientation='landscape'
                                           ,maxage=0)

        server.workbooks.populate_pdf(wb, pdf_options)

        print(f'Path:{os.getcwd()}')
        with open(pdf_file_name, 'wb') as f:
            f.write(wb.pdf)
            print('[PDF Generated]')