How to Generate a PDF Report from Snowflake Query Results
Run a Snowflake SQL query on a schedule, turn the result into a formatted PDF report with a title, summary and table, and email it or save it to your File Store, with no BI licence for the people who receive it.
What This Integration Does
Plenty of people need a Snowflake number every week but will never open a worksheet or a dashboard: store managers, suppliers, the board. A PDF in their inbox is what they read. This Spojit workflow runs your SQL through the Snowflake SQL API, passes the rows to the PDF Tools connector's create-pdf tool, which lays them out as a paginated table under a heading and a short summary, and sends the file by email or saves it to your File Store. An optional AI step writes the summary paragraph from the numbers.
Every run executes the query fresh, so the report always reflects current data, and nothing in Snowflake is changed. The query runs under a role you choose, so the report can only ever contain what that role is allowed to see.
Prerequisites
- A Snowflake user for the integration (ideally
TYPE = SERVICE) with a role that can use the warehouse and read the tables in the query. - A programmatic access token (PAT) for that user, created in Snowsight from the user's profile under Programmatic access tokens, restricted to the reporting role. Snowflake shows the token once; copy it.
- A network policy that allows the token to be used. By default Snowflake requires the user to be covered by a network policy before a PAT can authenticate; your Snowflake admin can add one, or relax the requirement with an authentication policy.
- An HTTP Requests connection in Spojit with Base URL
https://YOUR_ACCOUNT.snowflakecomputing.com(your account identifier, such asmyorg-myaccount) and Auth Method Bearer token set to the PAT.
Step 1: Schedule Trigger
Add a Trigger node with type Schedule, for example 0 7 * * 1 for 7 AM every Monday in the recipients' timezone.
Step 2: Run the Query
Add a Connector node on your Snowflake HTTP connection with http-post:
url:/api/v2/statementsheaders:{ "Content-Type": "application/json", "Accept": "application/json", "X-Snowflake-Authorization-Token-Type": "PROGRAMMATIC_ACCESS_TOKEN" }body:{ "statement": "SELECT region, COUNT(*) AS orders, ROUND(SUM(total), 2) AS revenue FROM sales.public.orders WHERE order_date >= DATEADD(day, -7, CURRENT_DATE) GROUP BY region ORDER BY revenue DESC", "timeout": 60, "warehouse": "REPORTING_WH", "role": "REPORTING", "database": "SALES", "schema": "PUBLIC" }
Name the output result. Snowflake returns the column definitions in result.data.resultSetMetaData.rowType (one entry per column, with its name) and the rows in result.data.data as arrays of strings.
Step 3: Get the Column Names
Add a Connector node on Array Tools with pluck, plucking name from {{ result.data.resultSetMetaData.rowType }}. Name it columns; the names are in {{ columns.items }}. These become the table headers in the PDF.
Step 4: Write a Summary (Optional)
Add a Connector node in Agent Mode on the Text Tools connector (its tools only reshape text, so the step only writes the summary) with a prompt such as: "Here are last week's orders and revenue by region: {{ result.data.data }} with columns {{ columns.items }}. Write two sentences for a store manager: the total, the best region, and anything unusual. No headings." Name the output summary.
Step 5: Create the PDF
Add a Connector node on PDF Tools with create-pdf:
title:Weekly sales by region(and add a Date & Timeformatstep namedweek_endingbefore this one for the date in the content)content:**Week ending:** {{ week_ending.result }} **Prepared:** automatically from Snowflake {{ summary }} ## Orders and revenue by regionrows:{{ result.data.data }}columns:{{ columns.items }}footer:Acme Pty Ltd - internalorientation:landscapeif the query returns many columns.
The table prints after the content, with its header repeated on every page. Name the output report; the file is {{ report.pdf }}, Base64-encoded.
Step 6: Deliver the Report
Email it with a Resend or SMTP Email step using send-email, adding an attachment with filename weekly-sales.pdf and content {{ report.pdf }}. Or save it with a File Store node (Save a file, content {{ report.pdf }}, content type application/pdf) to keep an archive of every week's report.
Tips
- Several sections: run more than one query and put the extra results in the
blocksinput as additionaltableblocks with their own headings. - Numbers as text: Snowflake returns every value as a string. Format numbers in SQL (
TO_CHAR(revenue, '999,999,990.00')) so the PDF shows them the way readers expect. - Long results: results over a certain size come back in partitions. Fetch the rest with
GET /api/v2/statements/{statementHandle}?partition=1and so on, or aggregate in SQL so the report stays readable. - Snowflake MCP alternative: if your account has Snowflake's managed MCP server set up, the Snowflake (Official MCP) connector lets an Agent Mode step answer questions in plain English. For fixed weekly reports, the SQL API keeps the query exact.
Common Pitfalls
- Asynchronous responses: if a query does not finish within the time Snowflake waits for a synchronous reply (about 45 seconds), Snowflake returns
202with astatementHandleinstead of rows and keeps running it;timeoutis when Snowflake cancels the statement altogether. PollGET /api/v2/statements/{statementHandle}in a Loop until it returns200, or make the query faster. - Case-sensitive context:
warehouse,role,databaseandschemamust match the names Snowflake shows inSHOWcommands, usually upper case. - Token rejected: a PAT fails if the user is not covered by a network policy (when one is required), if the role restriction does not include the role in the request, or after the token expires. Check the user's login history in Snowsight.
- Escaping SQL in JSON: double quotes inside the SQL must be escaped as
\"in the body. Prefer single quotes for string literals.
Testing
Run the workflow manually with LIMIT 20 on the query and open the PDF in your File Store. Check the columns, number formatting and page breaks, then remove the limit and turn on the schedule.