Log Entry
Blob.toPdf Rendering Update
If you generate invoices, statements, or letters from Apex, this update is worth treating like a mini migration.
The code call stays the same, but the renderer changes, and rendering changes are where teams get surprised.
Quick snapshot (What / Where / When / Why)
- What:
Blob.toPdf()now uses the Visualforce PDF rendering service. - Where: Lightning Experience and Salesforce Classic in Enterprise, Performance, Unlimited, and Developer editions.
- When: enforced in Summer '26.
- Why: better font support, better multibyte handling, and consistent behavior with Visualforce PDF rendering.
What stays the same
Blob.toPdf(String input)is still the API shape.- You still pass a
String. - You still get back a
Blob.
So this is not a refactor-heavy release. It is mostly a rendering-fidelity release.
How I would use this in a real org
I would do this in four steps:
- Make font and print rules explicit in every PDF template string.
- Add one canary PDF generator so you can compare before/after output reliably.
- Run multilingual smoke tests (especially if you support non-Latin scripts).
- Compare output for wrapping/page breaks before turning the update on in production.
That sequence catches almost all "it compiles but pagination changed" incidents.
Example 1: Minimal Blob.toPdf() + save as File
public with sharing class InvoicePdfService {
public static Id generateInvoice(Id publishToRecordId, String invoiceNumber, Decimal total) {
String html =
'<html><body>' +
'<h1>Invoice ' + String.escapeSingleQuotes(invoiceNumber) + '</h1>' +
'<p>Date: ' + String.valueOf(Date.today()) + '</p>' +
'<p>Total: $' + String.valueOf(total.setScale(2)) + '</p>' +
'</body></html>';
Blob pdfBlob = Blob.toPdf(html);
ContentVersion cv = new ContentVersion(
Title = 'Invoice-' + invoiceNumber,
PathOnClient = 'invoice-' + invoiceNumber + '.pdf',
VersionData = pdfBlob,
FirstPublishLocationId = publishToRecordId
);
insert cv;
return cv.Id;
}
}
Example 2: Make layout deterministic (font + page rules)
String html =
'<html><head><style>' +
'@page { size: A4; margin: 16mm; }' +
'body { font-family: Arial, sans-serif; font-size: 12px; line-height: 1.35; }' +
'.section { page-break-inside: avoid; margin-bottom: 10px; }' +
'.label { font-weight: 600; }' +
'</style></head><body>' +
'<div class="section"><p class="label">Billing Address</p><p>...</p></div>' +
'<div class="section"><p class="label">Line Items</p><p>...</p></div>' +
'</body></html>';
Blob pdfBlob = Blob.toPdf(html);
If you only do one thing for this update, do this.
Example 3: Multibyte smoke test you can run in UAT
String html =
'<html><head><style>' +
'body { font-family: sans-serif; font-size: 12px; }' +
'</style></head><body>' +
'<p>English: Invoice ready</p>' +
'<p>日本語: 請求書を作成しました</p>' +
'<p>العربية: تم إنشاء الفاتورة</p>' +
'<p>ไทย: ออกใบแจ้งหนี้เรียบร้อยแล้ว</p>' +
'</body></html>';
Blob pdfBlob = Blob.toPdf(html);
I use a snippet like this to validate that multilingual output still looks right after engine changes.
Example 4: Canary doc for before/after comparison
public with sharing class PdfCanaryService {
public static Id generateCanary(Id publishToRecordId, String label) {
String safeLabel = String.escapeSingleQuotes(label);
String html =
'<html><head><style>' +
'body { font-family: Arial, sans-serif; font-size: 12px; line-height: 1.35; }' +
'.block { margin-bottom: 8px; }' +
'</style></head><body>' +
'<div class="block">Label: ' + safeLabel + '</div>' +
'<div class="block">Timestamp: ' + String.valueOf(Datetime.now()) + '</div>' +
'<div class="block">Long wrap test: ConnectApi.RecordUi.getPicklistValuesByRecordType(...)</div>' +
'</body></html>';
Blob pdfBlob = Blob.toPdf(html);
ContentVersion cv = new ContentVersion(
Title = 'PDF-Canary-' + safeLabel,
PathOnClient = 'pdf-canary-' + safeLabel + '.pdf',
VersionData = pdfBlob,
FirstPublishLocationId = publishToRecordId
);
insert cv;
return cv.Id;
}
}
Run this against a stable input set before and after activation, then compare page count and break positions.
Activation path (the practical click path)
In Setup:
- Go to Release Updates.
- Find Use Visualforce PDF Rendering Service with Apex Blob.toPdf().
- Follow testing and activation there.
For your exact major-release timing, use Trust Status for your instance and check Maintenance.
Final take
This is a good platform change.
Just do not treat it like "no impact because method signature is unchanged." Treat it like a renderer swap, lock down typography, and verify output intentionally before Summer '26 enforcement.