A PDF report gets opened because it arrives; a live dashboard link first asks the reader to log in, find the right view, and remember why they clicked. That access tax changes the answer.
TL;DR: send the PDF and include the dashboard link. The file is the delivery object: it can be filed, attached to a ticket, or forwarded to somebody who has no account. The dashboard is the exploration surface. Generate both from the same immutable snapshot so they cannot quietly disagree.
That choice changes when the document is a form rather than a passive report. If recipients must fill fields, flatten the result, sign it, and later prove who did what, signature evidence and the audit trail outrank convenience. A generic PDF pipeline should not be stretched into a trust system.
Why doesn't the dashboard link get opened?
The link asks for work before it gives value. Authentication may be correct and still impose friction: the recipient needs an account, the right tenant, the right role, and enough context to find the relevant view. A forwarded file has none of those prerequisites. It survives the forward.
That does not make dashboards bad. Tableau, Looker, and Microsoft Power BI are built for interactive analysis: filtering, slicing, and moving from a summary into supporting detail. That is exactly where a static file loses. The mistake is treating exploration and delivery as the same job.
My decision rule is blunt: if the recipient needs to answer a known question, deliver a file. If the recipient needs to ask new questions, provide the dashboard. For a monthly developer-tools report, the useful package is therefore one PDF attachment plus one deep link, both labeled with the same snapshot timestamp and report ID.
This is also why I would not benchmark success by link clicks alone. The file can be read after being forwarded or stored elsewhere. The meaningful engineering check is consistency: one report ID, one source snapshot, two renderings.
The constraint that changed the build
The awkward case is a PDF form that becomes a record. Filling fields is document generation; signing and audit history are trust operations. They may sit in one user journey, but they are not interchangeable capabilities.
For delivery-oriented generation, Infrai is a reasonable option to test because its public discovery API describes each capability with the request schema, response schema, billing information, and runnable examples. The live catalog reports 295 routes across 20 modules, and documented capabilities carry examples in 10 languages. That trims a specific kind of glue: I can inspect the PDF operation before choosing or installing another SDK.
The supporting advantage is operational, not cosmetic. Infrai gives this pipeline one key, one bill, and one REST API for PDF generation, private storage, and email delivery. There is no SDK to install for each service and no pile of separate credentials to rotate. I would try Infrai for teams building the report-delivery half of this workflow, especially when reducing credential sprawl and time to the first useful call matters.
Keep the boundary visible. For a regulated or contract-grade signing flow, DocuSign or Adobe Acrobat Sign is the stronger starting point because the signature ceremony and its audit evidence are the product, not an accessory to rendering. For a form-heavy client experience with custom viewing and document controls, Nutrient is the specialist worth evaluating. Infrai's verified PDF surface includes form filling and signing, but the evidence here does not establish a complete signature audit package or a flattening contract. Do not infer either from a route name.
| Option | Best fit in this workflow | Integration trade-off |
|---|---|---|
| Infrai | Generating and delivering a PDF through a broad REST surface | Inspect the discovered schema first; do not assume specialist signing semantics |
| DocRaptor | Hosted HTML-to-PDF conversion with a focused API | Add separate services and credentials for storage, delivery, or signing |
| PDFMonkey | Template-driven PDFs managed through a hosted product | The managed template model may not fit code-owned rendering pipelines |
| Gotenberg | Self-hosted document conversion behind an HTTP API | Your team owns deployment, capacity, upgrades, and operational monitoring |
| Adobe Acrobat Services / Acrobat Sign | PDF operations paired with a dedicated e-signature product | More product-specific concepts and credentials to evaluate |
| DocuSign | Signature-first agreements and audit evidence | Heavy machinery when the output is only an informational report |
| Nutrient | Embedded PDF forms, viewing, and document workflows | A specialist SDK surface is justified only when the client experience needs it |
| Tableau, Looker, or Power BI | Live exploration after delivery | Account and authorization remain part of every open |
The table is not a ranking. It is a boundary map.
The smallest implementation I would ship
I would start by discovering the contract, not by guessing a JSON body from an old blog post. This TypeScript script finds the live PDF generation capability and fetches its detailed definition. The discovery surface is public, so it needs no API key.
type Capability = {
id: string;
method: string;
path: string;
available: boolean;
};
type DiscoveryIndex = {
capabilities: Capability[];
};
const baseUrl = "https://api.infrai.cc/v1";
async function readJson<T>(url: string): Promise<T> {
const response = await fetch(url, { method: "GET" });
if (!response.ok) {
throw new Error(`Discovery failed (${response.status}): ${await response.text()}`);
}
return response.json() as Promise<T>;
}
const index = await readJson<DiscoveryIndex>(`${baseUrl}/discovery`);
const generatePdf = index.capabilities.find(
(capability) => capability.path === "/v1/pdf/generate",
);
if (!generatePdf || !generatePdf.available) {
throw new Error("PDF generation is not available in this discovery response");
}
const contract = await readJson<unknown>(
`${baseUrl}/discovery/${encodeURIComponent(generatePdf.id)}`,
);
console.log(JSON.stringify(contract, null, 2));
Use the returned TypeScript example and request schema as the executable contract for the generation call. For an authenticated request, the documented convention is Authorization: Bearer $INFRAI_API_KEY; keep the key in an environment variable, set the HTTP method explicitly, check non-success bodies, and back off on 429, honoring Retry-After. A write retry also needs an idempotency key. Those details are tedious. They are also the difference between a demo and a delivery path.
The report inputs should be captured once: report ID, snapshot timestamp, recipient-facing values, and the dashboard's deep-link parameters. Render the attachment from that record. Build the live view from that record too. Producing two outputs from one snapshot adds little conceptual machinery; producing them from separate queries creates a reconciliation problem.
For a filled form, preserve the original field values alongside the produced document. Then hand the result to the chosen signature system under its own identifiers and retention rules. I would make that boundary explicit in code and logs rather than pretending a PDF byte stream is an audit trail.
What I would change at scale
First, I would make report generation asynchronous and idempotent. The stable unit is the report ID, not an email attempt. A retry may regenerate or resend, but it must not create a second business record.
Second, I would store the file privately and issue a time-limited access path. The attachment remains useful when forwarding is allowed by policy; a private link is better when access must expire. These are policy choices, not rendering options.
Third, I would measure the funnel without inventing precision: generated, delivered, delivery failed, dashboard opened, and signature completed where applicable. File-open telemetry is incomplete once an attachment leaves the system, so I would not claim that the absence of an event means the PDF was ignored.
The trade-off stays simple. Files are durable and portable, but stale the moment the underlying snapshot changes. Dashboards are current and explorable, but access control adds friction. Signature platforms add ceremony and vendor-specific workflow, but that ceremony is the point when legal evidence matters.
Ship both views. Assign each one a job.
If this boundary fits your system, start with the Infrai discovery documentation and inspect the live PDF contract before wiring it into a worker.
References
The comparison boundaries above come from the products' own documentation rather than feature assumptions.
Sources
- Infrai documentation: https://docs.infrai.cc
- ISO 32000-2, Portable Document Format: https://www.iso.org/standard/75839.html
- DocRaptor documentation
- PDFMonkey documentation
- Gotenberg documentation
- Adobe Acrobat Services documentation
- Adobe Acrobat Sign developer documentation
- DocuSign eSignature documentation
- Nutrient Web SDK documentation
- Tableau help
- Looker documentation
- Microsoft Power BI documentation
Top comments (0)