How to Take Screenshots and Generate PDFs in Dart and Flutter
The standard Flutter approach to PDF generation — the pdf package widget tree — falls apart with complex HTML templates and CSS layouts. Here's the simpler path: one HTTP call, binary response. Captures your HTML exactly as it renders in a browser.
The standard Flutter approach to PDF generation is the pdf package — you build documents by constructing a widget tree in Dart, laying out text and images programmatically. It works well for simple documents but falls apart with complex HTML templates, CSS layouts, or anything that needs to match a web-rendered design exactly.
Here's the simpler path: send your HTML to PageBolt, get back a pixel-perfect PDF. One HTTP call, binary response.
Dart (server-side / CLI)
No dependencies beyond dart:io and dart:convert:
import 'dart:convert';
import 'dart:io';
Future<Uint8List> screenshot(String url) async {
final apiKey = Platform.environment['PAGEBOLT_API_KEY']!;
final client = HttpClient();
final request = await client.postUrl(
Uri.parse('https://pagebolt.dev/api/v1/screenshot'),
);
request.headers.set('x-api-key', apiKey);
request.headers.set('content-type', 'application/json');
request.add(utf8.encode(jsonEncode({
'url': url,
'fullPage': true,
'blockBanners': true,
})));
final response = await request.close();
final bytes = await consolidateHttpClientResponseBytes(response);
client.close();
return bytes;
}
void main() async {
final image = await screenshot('https://example.com');
await File('screenshot.png').writeAsBytes(image);
print('Screenshot saved (${image.length} bytes)');
}
Flutter — using http package
Add to pubspec.yaml:
dependencies:
http: ^1.2.0
import 'package:http/http.dart' as http;
import 'dart:convert';
class PageBoltClient {
static const _baseUrl = 'https://pagebolt.dev/api/v1';
final String _apiKey;
PageBoltClient(this._apiKey);
Future<Uint8List> screenshot(String url) async {
final response = await http.post(
Uri.parse('$_baseUrl/screenshot'),
headers: {
'x-api-key': _apiKey,
'Content-Type': 'application/json',
},
body: jsonEncode({
'url': url,
'fullPage': true,
'blockBanners': true,
}),
);
if (response.statusCode != 200) {
throw Exception('PageBolt error ${response.statusCode}: ${response.body}');
}
return response.bodyBytes;
}
Future<Uint8List> pdfFromUrl(String url) async {
final response = await http.post(
Uri.parse('$_baseUrl/pdf'),
headers: {'x-api-key': _apiKey, 'Content-Type': 'application/json'},
body: jsonEncode({'url': url, 'blockBanners': true}),
);
return response.bodyBytes;
}
Future<Uint8List> pdfFromHtml(String html) async {
final response = await http.post(
Uri.parse('$_baseUrl/pdf'),
headers: {'x-api-key': _apiKey, 'Content-Type': 'application/json'},
body: jsonEncode({'html': html}),
);
return response.bodyBytes;
}
}
Flutter — share PDF via Share sheet
import 'package:share_plus/share_plus.dart';
import 'package:path_provider/path_provider.dart';
Future<void> sharePdf(String invoiceHtml) async {
final pagebolt = PageBoltClient(const String.fromEnvironment('PAGEBOLT_API_KEY'));
final pdfBytes = await pagebolt.pdfFromHtml(invoiceHtml);
final dir = await getTemporaryDirectory();
final file = File('${dir.path}/invoice.pdf');
await file.writeAsBytes(pdfBytes);
await Share.shareXFiles(
[XFile(file.path, mimeType: 'application/pdf')],
subject: 'Your Invoice',
);
}
Flutter — display PDF inline
Using syncfusion_flutter_pdfviewer:
import 'package:syncfusion_flutter_pdfviewer/pdfviewer.dart';
class InvoiceScreen extends StatefulWidget {
final String invoiceHtml;
const InvoiceScreen({required this.invoiceHtml, super.key});
@override
State<InvoiceScreen> createState() => _InvoiceScreenState();
}
class _InvoiceScreenState extends State<InvoiceScreen> {
Uint8List? _pdfBytes;
@override
void initState() {
super.initState();
_load();
}
Future<void> _load() async {
final pagebolt = PageBoltClient(const String.fromEnvironment('PAGEBOLT_API_KEY'));
final bytes = await pagebolt.pdfFromHtml(widget.invoiceHtml);
setState(() => _pdfBytes = bytes);
}
@override
Widget build(BuildContext context) {
if (_pdfBytes == null) return const CircularProgressIndicator();
return SfPdfViewer.memory(_pdfBytes!);
}
}
No layout engine, no pdf package widget tree. The HTML template renders exactly as it does in a browser — fonts, CSS grid, images included.
Get Started Free
100 requests/month, no credit card
Screenshots, PDFs, and video recordings from your Flutter app — no pdf package widget tree, pixel-perfect HTML capture on iOS, Android, and server-side Dart.
Get Your Free API Key →