Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

Start with the path returned by the conversion call, not the path you requested. In React Native HTML-to-PDF workflows, a PDF can be generated successfully yet appear “missing” because it was written to the cache, an app-specific Android directory, or an iOS app container. Log the complete result (especially filePath), verify that the file exists and is readable, then decide whether you need to export it to user-accessible storage.

What “missing” can mean

Separate the problem into three questions:

  • Generation: Did the converter create a PDF at all?
  • Location: Where did the library actually write it?
  • Visibility: Can the user, a file manager, or another app access that location?

A valid file in app-private storage answers the first question but not necessarily the third. Treat a path mismatch as a storage-location issue until an existence check proves otherwise.

1. Log the resolved result and every option

The library documentation identifies filePath as the generated output path and documents cache as the default directory. Do not infer the final path from a requested directory string. Log the options you pass and the complete conversion result on the device where the failure occurs.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
import RNHTMLtoPDF from 'react-native-html-to-pdf';

export async function createPdf() {
  const options = {
    html: '<h1>Invoice</h1><p>Paid</p>',
    fileName: 'invoice-2026-09-29',
    // directory: 'Documents', // use only a value supported by your package/version
  };

  console.log('PDF options:', options);
  const result = await RNHTMLtoPDF.convert(options);
  console.log('PDF conversion result:', result);
  console.log('Resolved filePath:', result?.filePath);
  return result;
}

Keep the package version, React Native version, OS release, target SDK, requested directory, and returned path in the same diagnostic record. README behavior can change, so check the README for the exact version installed in your app.

2. Check the returned file inside the app

Use the exact returned path for an existence and readability test. With react-native-fs, a diagnostic check can look like this:

import RNFS from 'react-native-fs';

export async function inspectPdf(result) {
  const path = result?.filePath;
  if (!path) throw new Error('The converter returned no filePath');

  const exists = await RNFS.exists(path);
  console.log({ path, exists });

  if (!exists) {
    throw new Error(`PDF was not found at returned path: ${path}`);
  }

  const stat = await RNFS.stat(path);
  console.log({ size: stat.size, modified: stat.mtime });
  return path;
}

If this check succeeds, generation worked. The remaining issue is usually opening the file, exporting it, or looking in a different storage location. If it fails, capture the converter error and inspect malformed HTML, invalid options, timeouts, and native build logs before changing storage permissions.

3. Understand the directory the library actually uses

Situation What it means Next action
No directory supplied The README documents the cache directory as the default. Copy or export the file if it must survive cache cleanup or be visible to the user.
iOS custom directory The README documents Documents as the only accepted custom iOS directory value. Use that supported value, then add a share/export flow for access outside the app container.
Android path includes Android/data/<app>/files/ This is app-specific storage, not the public Download folder. A 2022 issue reports this exact type of mismatch. Use a modern shared-download or user-selected-document workflow.
Path exists but file manager cannot see it App-private storage can be readable by your app while hidden from ordinary public views. Export through Android document/storage APIs or the platform share sheet.

The issue report about an Android path under /storage/emulated/0/Android/data/<app>/files/Download/ is a historical case, not proof of a universal package defect. Always trust the returned path from your installed build.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

4. Choose the destination based on the user’s goal

Temporary in-app viewing

Keep the generated path private, verify it, and pass it to the PDF viewer or share sheet your app uses. Cache is acceptable only when losing the file after cache cleanup is acceptable.

Persistent app-owned storage

Use a directory supported by the package and platform, then confirm persistence on the target OS. On iOS, the documented custom value is Documents; do not assume arbitrary directory names are accepted.

User-selected save location

On Android, use the Storage Access Framework when the user should choose where a document is saved. Android 11 and later restrict selecting the Download directory through ACTION_OPEN_DOCUMENT_TREE, so that picker is not a general way to grant your app the whole Downloads folder.

App-managed Downloads entry

For Android 10 and later, Android documents that apps can add their own downloads to MediaStore.Downloads without storage-related permissions. Select the document API and export behavior that match your UX and target SDK rather than trying to expose an app-private path directly.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

5. Do not rely on obsolete Android permission fixes

Android’s scoped-storage guidance states that, for apps targeting Android 11, WRITE_EXTERNAL_STORAGE and the privileged WRITE_MEDIA_STORAGE permission provide no additional access. Adding that permission, or enabling requestLegacyExternalStorage, is therefore not a universal fix for a path that is private or invisible on current target SDKs.

Permissions also cannot turn an app-specific path into a public Downloads item. They address access policy; they do not change where the converter wrote the file. First prove the returned path exists, then implement the appropriate document or download workflow.

6. Export the verified PDF

A practical architecture is:

  1. Generate the PDF and retain result.filePath.
  2. Verify existence and a non-zero size.
  3. Present “Open”, “Share”, or “Save to…” actions.
  4. For Android, write a copy through the selected document or Downloads API rather than exposing the private source path.
  5. For iOS, use the share sheet or a document-export controller to move the file outside the app container.

Do not delete the source file until the export or share operation has completed. If you create a temporary copy, clean it up after success and keep failures available for diagnostics.

7. A complete diagnostic component

import { Alert } from 'react-native';
import RNHTMLtoPDF from 'react-native-html-to-pdf';
import RNFS from 'react-native-fs';

export async function makeAndInspectPdf() {
  const options = {
    html: '<html><body><h1>Report</h1></body></html>',
    fileName: `report-${Date.now()}`,
  };

  try {
    const result = await RNHTMLtoPDF.convert(options);
    const path = result?.filePath;
    if (!path) throw new Error('No filePath returned');

    const exists = await RNFS.exists(path);
    if (!exists) throw new Error(`Returned path does not exist: ${path}`);

    const info = await RNFS.stat(path);
    if (Number(info.size) === 0) throw new Error('PDF exists but is empty');

    console.log('PDF ready:', { path, size: info.size });
    return { path, size: Number(info.size) };
  } catch (error) {
    console.error('HTML-to-PDF failure:', error);
    Alert.alert('PDF error', String(error?.message || error));
    throw error;
  }
}

This code deliberately stops before platform-specific export. That boundary makes it clear whether the converter failed or the destination workflow failed.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Or skip the browser setup

If your real requirement is to obtain clean PDF or image captures of web pages rather than render HTML inside React Native, ScreenshotNeo provides a single HTTP endpoint and an MCP server for AI agents. It accepts cookie and consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed; response headers identify the page verdict and billing result.

For a screenshot or PDF request, see the ScreenshotNeo documentation. Example cURL:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

Python:

import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)

Node.js:

const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

ScreenshotNeo also offers full-page and element capture, device presets, PDF paper and page-range controls, custom CSS and JavaScript, waits, request blocking, headers, cookies, authentication, geolocation, caching, signed links, asynchronous webhooks, bulk capture, a usage API, and an OpenAPI specification. Its MCP tools are take_screenshot, get_page_info, and capture_pdf. Every plan includes every feature; 1,000 screenshots per month are free without a card, and paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account.

Troubleshooting by symptom

No filePath in the result

Log the entire result and catch the native error. Confirm the installed package version and that the conversion promise is awaited. A missing property is not evidence that a file exists elsewhere.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The returned path does not exist

Check the conversion exception, HTML input, filename characters, and native build logs. Reproduce with minimal HTML and a simple filename before changing storage settings.

The path exists, but a file manager shows nothing

Compare the path with public storage. A path under Android app-specific directories is private by design. Export through a document or Downloads API.

It works on one Android version only

Record OS release and target SDK, then review scoped-storage behavior for that combination. Avoid assuming an old permission workaround applies to Android 11-targeting builds.

iOS rejects the requested directory

Use the documented Documents value for a custom iOS directory and verify behavior against your exact library version. Use a share/export controller for user access outside the container.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The PDF opens, then disappears later

The default cache location may be cleaned by the operating system. Move or export files that must remain available, and do not promise persistence from a temporary path.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

What to include in a bug report

  • React Native and HTML-to-PDF package versions.
  • OS release, device type, and Android target SDK.
  • Complete conversion options with sensitive values removed.
  • Complete returned object and exact filePath.
  • Existence, size, and readability results.
  • Whether the complaint is generation, inaccessible path, or user-facing visibility.

That information distinguishes a converter failure from a correct write to an unexpected storage scope. Historical issue reports demonstrate path mismatches, but they do not establish one version-independent cause.

Frequently Asked Questions

Does setting directory: 'Download' guarantee the public Android Downloads folder?

No. The resolved filePath is authoritative. An Android path under an app-specific Android/data/.../files/ directory is different from public Downloads and must be exported through an appropriate platform API.

Which iOS directory value does the package document for custom output?

The README documents Documents as the only accepted custom iOS directory value. Verify the README for the exact package version you ship.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Will WRITE_EXTERNAL_STORAGE fix Android 11 path problems?

Not for apps targeting Android 11: Android states that this permission provides no additional access. Use the document or shared-download workflow that matches your intended user experience.

How can I tell whether generation or visibility is broken?

Check the returned filePath with an in-app existence and size test. A readable file proves generation; inability to see it elsewhere indicates an export or storage-scope issue.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.