SheetRender Blog

CSV to PDF: One File Per Record, Not One Giant Table

By Josh ·

A CSV becomes a PDF in one of two ways: the whole table on a page, or one file per row. Decide which job you have before you pick a tool, because most of the tools only do the first.

What is the fastest way to convert a CSV to PDF? Open it in Google Sheets or Excel, then download or export as PDF. You don't need a separate converter.

Convert a CSV to PDF in two minutes

The CSV is a table, and you want that table on a page you can attach or print. The spreadsheet app you already have does it.

Google Sheets

  1. File > Import and upload the .csv. "Replace current sheet" keeps you in one file. "Insert new sheet(s)" makes a tab you will have to find again later.
  2. Freeze the header: View > Freeze > 1 row.
  3. File > Download > PDF document.
  4. In the print pane, set the page to landscape and scale to Fit to width. Tick Repeat frozen rows so the header survives onto page 2.

Skip step 2 and that tick does nothing: Sheets repeats frozen rows, and you froze none. Page 2 then starts mid-table with no column names, and whoever gets the PDF has to guess.

Excel

  1. Open the file with Data > From Text/CSV so you can set the delimiter and the encoding yourself. Double-clicking the .csv makes Excel guess both from your regional settings, and the guess goes wrong often enough to matter.
  2. Page Layout: Orientation Landscape. Set Width to 1 page.
  3. Page Layout > Print Titles, and put $1:$1 in Rows to repeat at top.
  4. File > Export > Create PDF/XPS, or File > Save As and pick PDF.

Print Titles is the setting that disappears from muscle memory.

From a terminal, LibreOffice does the same conversion with no window:

libreoffice --headless --convert-to pdf data.csv

On some machines the binary is named soffice instead. You get one table-shaped PDF of the whole file.

I wouldn't upload a customer list to one of the free online converters ranking above this page. Excel and LibreOffice convert it without the file leaving your machine, and Sheets at least keeps it inside an account you already trust with your email.

If that printout is what you came for, stop. The rest of this post is a different file.

CSV to PDF, one file per row

The other job is the batch. Each row is a person or an invoice, and the files you want are invoice-acme.pdf and invoice-birch.pdf, sitting in one folder. File > Download can't name a file after column B. It can't hide the other rows either.

The three routes below are the ones that do it.

Starting from a Word document instead? The macro that splits a merge into separate PDFs covers it. And if what you're really sending is email, the Google Sheets mail merge guide is the better page. A recurring report pack, one per client every week, has its own guide: automated PDF reports.

A fuller survey of hosted PDF tools, including e-sign and generation APIs, is convert a spreadsheet to PDF automatically. This post stays on the CSV: which routes read the file as it is, and which want it in Google Sheets first.

A Python script that writes one PDF per row

If you can run Python, this is the route that takes the CSV as it sits. No import into Sheets. No add-on.

Install the PDF library, then run the script in the folder that holds invoices.csv:

pip install fpdf2
import csv
from fpdf import FPDF

# assumes columns are name, invoice_id, amount, in that order
with open("invoices.csv", newline="", encoding="utf-8") as handle:
    rows = csv.reader(handle)
    next(rows)
    for name, invoice_id, amount in rows:
        pdf = FPDF()
        pdf.add_page()
        pdf.set_font("Helvetica", size=12)
        pdf.cell(0, 10, f"Invoice {invoice_id}", new_x="LMARGIN", new_y="NEXT")
        pdf.cell(0, 10, f"Bill to: {name}", new_x="LMARGIN", new_y="NEXT")
        pdf.cell(0, 10, f"Amount due: ${amount}", new_x="LMARGIN", new_y="NEXT")
        pdf.output(f"invoice-{invoice_id}.pdf")

That's 15 lines, including the comment and the blank line after the imports. next(rows) throws away the header. Delete that line if your file has no header, or the first record never becomes a PDF. Change the invoice-{invoice_id} pattern if the filename should come from a different column.

This is the naive version. It won't resume after a crash: you get however many PDFs it wrote and no record of which rows they came from. It dies on the first row with a stray comma in an unquoted address field, because four values won't unpack into three names, and the traceback doesn't say which row. Making the page look like last year's invoice in drawing commands is its own project, and a longer one than the loop.

Helvetica is a built-in fpdf2 font, and the built-ins are Latin-1. José is fine. A Polish ł raises FPDFUnicodeEncodingException unless you register a TTF with add_font and select it with set_font. Semicolon-delimited files also need a dialect on the reader (delimiter=";"). The script above assumes a comma and UTF-8, which is what most systems write and what Excel often does not.

Fine for a hundred rows and a page that can look like a data sheet. A poor system for something other people have to rerun.

Autocrat, after you import the CSV

If you don't want to write that script, Autocrat (opens in a new tab) is the free non-code route that still gives you one PDF per row. It is a Google Workspace add-on from New Visions Cloudlab. You tag a Google Docs or Google Slides template with <<Name>> placeholders and point each tag at a column. Set the job to one file per row, with PDF as the type.

The catch that matters for a CSV is earlier than any of that. Autocrat reads Google Sheets only. The file has to be imported first. A CSV that arrives fresh every week means an import step every week.

How you import decides whether the mapping survives next week. File > Import > Replace current sheet keeps the mapping, because the tab Autocrat points at still exists and the headers still match. Import into a brand new spreadsheet instead and the old job keeps running against last Monday's rows without telling you. Then you rebuild the merge in the new file, tag by tag.

There is a click-by-click walkthrough in the bulk certificate guide if you want the Slides version of the template. Same add-on, same multiple-output mode.

File names come from your columns and the finished PDFs land in a Drive folder. It can email each row its own file, and either a clock or a form submission can start the run. For a one-off after a single import, I'd use it and stop reading.

It runs as Apps Script inside your Google account, so it inherits that account's ceilings: six minutes per execution, and triggered scripts share 90 minutes of total runtime per day on a consumer account, 6 hours on Google Workspace (Google's quota table (opens in a new tab)). Six minutes sounds like plenty until you watch a run: each row is a full document copy plus a PDF export, and the clock covers all of them. A big batch stops partway, with Service invoked too many times in the merge log when you're lucky and nothing at all when you're not.

The output looks like the Docs or Slides template you tagged. That is either what you wanted or the reason you came back to this page.

SheetRender, if the finished document already exists

SheetRender is our product, so read this section knowing that.

You upload the finished document you already send, a PDF or a screenshot of one, and we rebuild it as a template with its fields mapped to your columns. The data source can be the CSV as it sits, no import and no tagging. An .xlsx or a connected Google Sheets file works the same way. Check the mapping, generate, and every row comes back as its own PDF, zipped or one at a time.

Drive delivery and per-row email are built in. Schedules are paid only. You choose how often the run fires and, for daily or weekly runs, at what hour; a run can also be held to rows added since the last one.

The output is a PDF and nothing else. There is no editable Docs file at the end, and nothing gets written back into your sheet the way Autocrat keeps a status column. E-signatures and payment links aren't ours. Your own code can call the REST API, which covers one-off renders, saved templates, and batch jobs. Your data also leaves Google: the uploaded file stays with your project until you delete it, and building the template sends the column names plus a small sample of rows to Anthropic, the AI vendor that reconstructs the layout. For some HR and school lists that's a policy conversation, and Autocrat wins it because the merge never leaves Drive.

Free is 50 documents a month, 2 active templates, a "Made with SheetRender" footer on every page, 50 emails a month, and 0 scheduled runs, and generated documents are kept for 30 days. The footer is on document one; it doesn't wait until you hit the cap. A batch of 40 runs. A 60-row invoice batch doesn't fit. Starter is $19 a month for 1,500 documents and one active schedule (pausing it frees the slot). Pro is $49 for 10,000 documents, no schedule cap, and the 15-minute option.

The rebuilt template still needs a pass on tight spacing and dense tables, and a bad scan produces a bad template. Free will run a real batch up to those 50 documents; clean output to send is where a paid tier starts.

Which route for which job

This table routes the two jobs above. If you want the hosted tools compared on price and scheduling mechanics, use the 8-tool spreadsheet-to-PDF post and come back.

RouteCostTakes a CSV directly?Output shapeRuns unattended?
Spreadsheet-app exportFree in Sheets; Excel needs its Microsoft licenseExcel opens the file. Sheets needs an import.One PDF of the whole tableNo
LibreOffice CLIFreeYesOne PDF of the whole tableOnly if you put the command on a timer
Python scriptFreeYesOne PDF per row, laid out in codeOnly if you wrap it yourself
AutocratFreeNo. Import into Google Sheets first.One PDF per row from a Docs or Slides templateYes. Time and form triggers.
SheetRenderFree: 50 docs/month with a footer. $19/month for 1,500. $49/month for 10,000.Yes. Also .xlsx and Google Sheets.One PDF per row, from an example document you uploadPaid tiers: one active schedule on Starter, uncapped on Pro

Quick answers

How do I convert a CSV to PDF without Excel? Open it in Google Sheets and use File > Download > PDF document, or run libreoffice --headless --convert-to pdf data.csv. Both give you one table-shaped file. Neither needs a Microsoft license.

Can I convert a CSV to PDF for free? Yes. LibreOffice costs nothing and keeps the file on your machine, and Sheets adds no charge beyond the Google account you already have. Excel isn't free, but if you own it the export is included. For one file per row, the Python script and Autocrat cost nothing either; SheetRender's free tier is 50 watermarked documents a month with no scheduled runs.

How do I convert each row of a CSV to a separate PDF? Use something that treats a row as a document. If you can run code, the Python script above writes one file per row and names each from a column. The no-code question is whether the CSV can live in Google Sheets, which is Autocrat after an import, or has to be read as it sits, which is where SheetRender comes in.

Why does my CSV look wrong when I convert it? Two usual causes, and they show up before any PDF setting. European files often use a semicolon (or a tab) where the importer expects a comma, so the whole row lands in one column. Encoding is the other: left to guess, Excel can read UTF-8 names in the local code page and turn José into mojibake. Use Data > From Text/CSV in Excel or the import preview in Sheets, set the delimiter and UTF-8 there, then export. If LibreOffice guesses wrong, open the file in Calc and fix both in the Text Import dialog before exporting; the command-line --infilter override exists but wants a full filter-option string.

Which should you pick?

  • A printout of the table, once: Sheets or Excel export. LibreOffice if you already live in a terminal.
  • One file per row and you can live with a plain page: the Python script.
  • One file per row and no code, after a single Sheets import: Autocrat.
  • A document you already have, and a CSV that should not need re-importing: SheetRender. Use a paid tier if the run has to fire without you.

If you came here for a printout, the export menu was the whole answer and everything after the turn was someone else's problem. If you came here with a roster, the question is how often the file shows up. A single CSV is an import plus Autocrat, or fifteen lines of Python if nobody has to admire the result. A file that lands every Monday is a different process, and the import click is the part that fails first.

Ready to turn every row into its own polished PDF?

Free plan · No credit card required