# Bulk Certificate & Diploma PDF Generator (`egra_van/bulk-certificate-pdf-generator`) Actor

Turn a list of names (Google Sheet, CSV or JSON) into print-ready PDF certificates and diplomas. 3 designs or your own HTML, QR verification codes, ZIP and merged PDF output. Full Unicode: Latin, diacritics, Cyrillic.

- **URL**: https://apify.com/egra\_van/bulk-certificate-pdf-generator.md
- **Developed by:** [Argentin Vazdautan](https://apify.com/egra_van) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $4.10 / 1,000 certificate / diploma pdfs

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Bulk Certificate & Diploma PDF Generator

Turn a list of names into **print-ready PDF certificates and diplomas** in seconds. Paste a Google Sheet link, pick a design, and get one PDF per person, plus a ZIP of everything and (optionally) one merged PDF for printing.

Built for **schools, online course creators, training companies, event organizers, coding clubs and HR teams** who hand out certificates in batches.

### What it does

- 📄 **One PDF per row** of your Google Sheet, CSV or JSON list
- 🎨 **3 ready designs**: Classic certificate, Modern certificate, Kids diploma, or **your own HTML/CSS**
- ✍️ **Personalize any text** with `{{column}}` placeholders: `{{name}}`, `{{course}}`, `{{hours}}`, `{{grade}}`, anything in your sheet
- 🔐 **QR verification codes** and unique certificate IDs (e.g. `SCHOOL-2026-0001`)
- 🌍 **Full Unicode**: accents and diacritics (é, ü, ș, ț, ă…) and **Cyrillic** render correctly, with embedded fonts
- 📦 **ZIP download** of all PDFs and an optional **merged PDF** for one-click printing
- 🖨️ A4 or US Letter, landscape or portrait
- ⚡ About 200 certificates per minute

### How to use it

1. Put your list in a Google Sheet. First row = column names, e.g. `name | course | date`.
2. Share the sheet: **Anyone with the link → Viewer**.
3. Paste the link into **Google Sheet or CSV link**.
4. Choose a design, write your title and text (use `{{course}}` etc. to insert columns).
5. Click **Start**. Download the ZIP or the individual PDFs from the **Output** tab.

### Input example

```json
{
  "csvUrl": "https://docs.google.com/spreadsheets/d/XXXX/edit#gid=0",
  "template": "certificate-classic",
  "title": "Certificate",
  "subtitle": "of completion",
  "body": "Awarded for successfully completing {{course}} ({{hours}} hours).",
  "date": "{{date}}",
  "issuer": "Bright Minds Academy",
  "signature1Name": "Jane Doe",
  "signature1Title": "Director",
  "accentColor": "#1f4e8c",
  "addQrCode": true,
  "verifyUrlTemplate": "https://brightminds.example/verify?id={{certificateId}}",
  "certificateIdPrefix": "BMA-2026-",
  "mergeIntoOnePdf": true
}
```

You can also pass rows directly with `records` (JSON array), `csvText` (pasted CSV), or `datasetId` (items from another Apify Actor).

### Output

Each generated document appears in the dataset:

```json
{
  "name": "Maria Popescu",
  "fileName": "Maria Popescu.pdf",
  "certificateId": "BMA-2026-0001",
  "pdfUrl": "https://api.apify.com/v2/key-value-stores/.../records/0001-maria-popescu.pdf"
}
```

The run's key-value store also contains:

- `all-documents.zip`: every PDF in one ZIP
- `all-documents-merged.pdf`: all certificates in one file (if enabled)
- `OUTPUT`: summary with links

### Pricing

**Pay per document.** You only pay for PDFs that are actually generated. Empty rows are skipped for free. You can set a maximum spend per run, and the Actor stops cleanly when it is reached.

### Your own design

Choose **Custom HTML** and write your page with placeholders:

```html
<div class="page" style="padding:30mm; font-family:'Playfair Display'">
  <h1>{{name}}</h1>
  <p>completed {{course}} on {{date}}</p>
  <img src="{{qrDataUrl}}" style="width:25mm">
</div>
```

Available fonts: **Montserrat, Playfair Display, Great Vibes** (script), **Lora**. All values are HTML-escaped automatically.

### Automate it

Run it from **Make, Zapier, n8n** or the Apify API. For example, when a student finishes a course in your LMS, add a row and generate the certificate automatically. The `pdfUrl` in the output can be emailed directly.

### FAQ

**My Google Sheet link doesn't work.** Set sharing to *Anyone with the link can view*. You can also use *File → Share → Publish to web → CSV*.

**Can I use a different name column?** Yes, set **Name column** (e.g. `full_name`).

**Can each person get a different course or date?** Yes. Add a column and reference it with `{{column}}`.

**Is my data stored?** Only in your own Apify storage for this run, under your account's retention settings.

### n8n template

Send every person their certificate by email straight from a Google Sheet: import [this ready-made n8n workflow](https://github.com/Egrarobo/apify-actors/blob/main/n8n-templates/certificates-from-google-sheets.json) (Workflows → Import from file). It calls this Actor with an HTTP Request node, so no community node is needed.

# Actor input Schema

## `csvUrl` (type: `string`):

Link to a Google Sheet (sharing: 'Anyone with the link can view') or to a CSV file. The first row must contain column names, e.g. name, course, date.

## `csvText` (type: `string`):

Paste rows directly. First row = column names.

## `records` (type: `array`):

Array of objects, e.g. \[{"name": "Anna", "course": "Robotics"}]. Used before CSV if both are given.

## `datasetId` (type: `string`):

Use items from an existing Apify dataset (e.g. output of another Actor).

## `nameField` (type: `string`):

Column that holds the person's name. Rows where it is empty are skipped.

## `template` (type: `string`):

Design.

## `title` (type: `string`):

Supports {{column}} placeholders.

## `subtitle` (type: `string`):

Subtitle.

## `body` (type: `string`):

Use {{column}} to insert any column from your list, e.g. {{course}}, {{hours}}, {{grade}}.

## `date` (type: `string`):

Fixed text or {{date}} to take it from your list.

## `issuer` (type: `string`):

Organization.

## `logoUrl` (type: `string`):

Public link to a PNG/JPG/SVG logo.

## `accentColor` (type: `string`):

Hex color, e.g. #1f4e8c.

## `signature1Name` (type: `string`):

Signature 1 — name.

## `signature1Title` (type: `string`):

Signature 1 — role.

## `signature2Name` (type: `string`):

Signature 2 — name.

## `signature2Title` (type: `string`):

Signature 2 — role.

## `pageSize` (type: `string`):

Paper size.

## `orientation` (type: `string`):

Orientation.

## `addQrCode` (type: `boolean`):

Adds a QR code and certificate ID in the corner.

## `verifyUrlTemplate` (type: `string`):

Where the QR code points, e.g. https://yourschool.com/verify?id={{certificateId}}

## `certificateIdPrefix` (type: `string`):

IDs become PREFIX0001, PREFIX0002… A 'certificateId' column in your list overrides this.

## `fileNameTemplate` (type: `string`):

Supports {{column}} placeholders.

## `outputZip` (type: `boolean`):

Create ZIP of all PDFs.

## `mergeIntoOnePdf` (type: `boolean`):

Also create one merged PDF (for printing).

## `maxDocuments` (type: `integer`):

Max documents.

## `customHtml` (type: `string`):

Your own page HTML with {{column}} placeholders. {{qrDataUrl}} gives the QR image. Wrap content in <div class="page">…</div>.

## `customCss` (type: `string`):

Extra CSS. Fonts available: Montserrat, Playfair Display, Great Vibes, Lora.

## Actor input object example

```json
{
  "csvText": "name,course,date\nMaria Popescu,Intro to Python,September 20 2026\nJohn Smith,Intro to Python,September 20 2026",
  "nameField": "name",
  "template": "certificate-classic",
  "title": "Certificate",
  "subtitle": "of completion",
  "body": "This certificate is awarded for successfully completing {{course}}.",
  "accentColor": "#1f4e8c",
  "pageSize": "A4",
  "orientation": "landscape",
  "addQrCode": false,
  "fileNameTemplate": "{{name}}",
  "outputZip": true,
  "mergeIntoOnePdf": false,
  "maxDocuments": 1000
}
```

# Actor output Schema

## `results` (type: `string`):

All result items of this run.

## `summary` (type: `string`):

Summary of the run with counts and download links.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "csvText": `name,course,date
Maria Popescu,Intro to Python,September 20 2026
John Smith,Intro to Python,September 20 2026`
};

// Run the Actor and wait for it to finish
const run = await client.actor("egra_van/bulk-certificate-pdf-generator").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "csvText": """name,course,date
Maria Popescu,Intro to Python,September 20 2026
John Smith,Intro to Python,September 20 2026""" }

# Run the Actor and wait for it to finish
run = client.actor("egra_van/bulk-certificate-pdf-generator").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "csvText": "name,course,date\\nMaria Popescu,Intro to Python,September 20 2026\\nJohn Smith,Intro to Python,September 20 2026"
}' |
apify call egra_van/bulk-certificate-pdf-generator --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,egra_van/bulk-certificate-pdf-generator"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/VMoTwh3GddX2SHsuf/builds/cVZlwMe1Ku1ImMR0c/openapi.json
