> ## Documentation Index
> Fetch the complete documentation index at: https://developer.dromo.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Importing a PDF table with a Custom Parser

## Overview

In this guide, we'll build a [custom file parser](/reference/custom-file-parsers) to support PDF uploads using the PDFTables API to extract tables from PDFs.

## Getting Started

For our example we're importing users from a table in a PDF document.

<img src="https://mintcdn.com/dromo-88ab5238/JhcPQeQwUXntQUrW/images/guides/customParserPDF.png?fit=max&auto=format&n=JhcPQeQwUXntQUrW&q=85&s=a6b39304e591f657ef729466b41d4256" alt="PDF Contents" width="976" height="1042" data-path="images/guides/customParserPDF.png" />

We'll rely on [PDFTables](https://pdftables.com/) API to parse the PDF into a CSV string. Once we have a CSV string, we'll use an additional external library, [PapaParse](https://www.papaparse.com/), to parse the CSV string into a two dimensional array of data for Dromo to receive.

<Info>
  To use this demo you'll need to get your own [paid API key from PDFTables](https://pdftables.com/pricing).
</Info>

## Adding the Custom Parser to Dromo

Dromo provides an [interface for implementing custom file parsing](/reference/custom-file-parsers). We need to specify the file extension(s) and the parsing logic that will be used to parse the file.

<CodeGroup>
  ```javascript JavaScript theme={null}
  ...
  const dromo = new DromoUploader("FRONTEND_API_KEY", fields, settings, user);

  dromo.registerFileParser({
    extensions: ["pdf"],
    parseFile: async (buffer, fileName) => {
      ...
    },
  });
  ```

  ```jsx React theme={null}
  ...
  <DromoUploader
    fileParsers={[
      {
        extensions: ["pdf"],
        parseFile: async (buffer, fileName) => {
          ...
        },
      },
    ]}>
    Import Users
  </DromoUploader>
  ```
</CodeGroup>

## Implementing PDF Parsing Logic

Dromo passes a `buffer: ArrayBuffer` and `fileName: string` to the `parseFile` callback. We will use the buffer to create a file that we can `POST` to the PDFTables API.

<CodeGroup>
  ```javascript theme={null}
  async (buffer, fileName) => {
    const myPDFTablesAPIKey = "<YOUR PDF TABLED API KEY>";
    const url = `https://pdftables.com/api?key=${myPDFTablesAPIKey}&format=csv`;
    const formData = new FormData();
    formData.append("file", new Blob([buffer]), fileName);
    
    const response = await fetch(url, {
      method: "POST",
      body: formData,
    });
    
    // text data response is a CSV string
    const data = await response.text();
    ...
  };
  ```
</CodeGroup>

If successful, the `response.text()` will contain a CSV string. Like this:

<CodeGroup>
  ```text theme={null}
  'my_filename,,,\nFirst,Last,Email,Food\nMichael,Phillips,jason@moxie.xyz,Apple\nMohit,Kukreja,info@hub.inc,Banana\nMark,Walz,vengat@klenty.com,Orange\nTonya,,team@buyerassist.io,Apple\nBen,Cohen,bad email,Banana\n,Simonyan,hello@markaaz.com,Orange\nSagar,Sagiraju,,Apple\nR2,Bewley,preena@klenty.com,Banana\nRuairi,Galavan,Info test,Orange\nAdam,Zelinski,info@medisponsor.com,Apple\nAnais,Mares,info@arrowxyz.com,Banana\nLucia,Lu,support@data-lead.com,Orange\nVishu,Gopal,admin@uptics.io,Strawberry\n1,,,\n'
  ```
</CodeGroup>

We need to convert this in to a two dimensional array. We'll use [PapaParse](https://www.papaparse.com/), a free package, to convert the string to the desired format.

<CodeGroup>
  ```javascript theme={null}
  import Papa from "papaparse";
  ...

  // text data response is a CSV string
  const data = await response.text();
  // 'names email select,,,\nFirst,Last,Email,Food\nMichael,Phillips...'

  const lines = Papa.parse(data).data as string[][];
  // [['names email select', '', '', ''], ['First', 'Last', 'Email', 'Food'], ['Michael', 'Phillips', 'jason@moxie.xyz', 'Apple']...]
  ...
  ```
</CodeGroup>

Ensure that every line in the two dimensional array is the same length, then return the data.

<CodeGroup>
  ```javascript theme={null}
  const maxLen = Math.max(...lines.map((row) => row.length));
  const result = lines.map((row) => {
    const padding = Array(maxLen - row.length).fill("");
    return [...row, ...padding];
  });

  return result;
  ```
</CodeGroup>

We're done! Let's try it in Dromo and see how it works.

Open the Dromo importer and observe the file extensions now include 'pdf'.

<img src="https://mintcdn.com/dromo-88ab5238/JhcPQeQwUXntQUrW/images/guides/extensions_include_pdf.png?fit=max&auto=format&n=JhcPQeQwUXntQUrW&q=85&s=171fb93207f5b175e6b96908c1454408" alt="extensions include pdf image" width="3690" height="1928" data-path="images/guides/extensions_include_pdf.png" />

Drag and drop your PDF test file. Your data should be properly parsed and loaded.

<img src="https://mintcdn.com/dromo-88ab5238/JhcPQeQwUXntQUrW/images/guides/parsed_pdf_data.png?fit=max&auto=format&n=JhcPQeQwUXntQUrW&q=85&s=2d11eb07dd5a24a133e6c29a8dcc39e6" alt="parsed pdf data" width="3694" height="1654" data-path="images/guides/parsed_pdf_data.png" />

## Full Complete Demo

<CodeGroup>
  ```javascript JavaScript theme={null}
  // Using PapaParse https://www.papaparse.com/ to parse the CSV string
  import Papa from "papaparse";

  const fields = [
    {
      label: "Email",
      key: "email",
      type: "email",
    },
    {
      label: "First Name",
      key: "firstName",
    },
    {
      label: "Last Name",
      key: "lastName",
    },
    {
      label: "Food",
      key: "food",
      type: "select",
      selectOptions: [
        { label: "Apple", value: "Apple" },
        { label: "Banana", value: "Banana" },
        { label: "Orange", value: "Orange" },
        { label: "Strawberry", value: "Strawberry" },
      ],
    },
  ];

  const settings = {
    importIdentifier: "Custom Parser Example",
  };

  const user = {
    id: "12345",
  };

  const dromo = new DromoUploader("FRONTEND_API_KEY", fields, settings, user);

  dromo.registerFileParser({
    extensions: ["pdf"],
    parseFile: async (buffer, fileName) => {
      const myPDFTablesAPIKey = "<YOUR PDF TABLED API KEY>";
      const url = `https://pdftables.com/api?key=${myPDFTablesAPIKey}&format=csv`;
      const formData = new FormData();
      formData.append("file", new Blob([buffer]), fileName);
      
      const response = await fetch(url, {
        method: "POST",
        body: formData,
      });
      
      // text data response is a CSV string
      const data = await response.text();
      const lines = Papa.parse(data).data as string[][];
      
      // Pad the lines to ensure they're all the same length
      const maxLen = Math.max(...lines.map((row) => row.length));
      const result = lines.map((row) => {
        const padding = Array(maxLen - row.length).fill("");
        return [...row, ...padding];
      });
      
      return result;
    },
  });
  ```

  ```jsx React theme={null}
  // Using PapaParse https://www.papaparse.com/ to parse the CSV string
  import Papa from "papaparse";
  ...

  <DromoUploader
    licenseKey={"FRONTEND_API_KEY"}
    user={{ id: "12345" }}
    fields={[
      {
        label: "Email",
        key: "email",
        type: "email",
      },
      {
        label: "First Name",
        key: "firstName",
      },
      {
        label: "Last Name",
        key: "lastName",
      },
      {
        label: "Food",
        key: "food",
        type: "select",
        selectOptions: [
          { label: "Apple", value: "Apple" },
          { label: "Banana", value: "Banana" },
          { label: "Orange", value: "Orange" },
          { label: "Strawberry", value: "Strawberry" },
        ],
      },
    ]}
    settings={{
      importIdentifier: "Custom Parser Example",
    }}
    fileParsers={[
      {
        extensions: ["pdf"],
        parseFile: async (buffer, fileName) => {
          const myPDFTablesAPIKey = "<YOUR PDF TABLED API KEY>";
          const url = `https://pdftables.com/api?key=${myPDFTablesAPIKey}&format=csv`;
          const formData = new FormData();
          formData.append("file", new Blob([buffer]), fileName);
          
          const response = await fetch(url, {
            method: "POST",
            body: formData,
          });
          
          // text data response is a CSV string
          const data = await response.text();
          const lines = Papa.parse(data).data as string[][];
          
          // Pad the lines to ensure they're all the same length
          const maxLen = Math.max(...lines.map((row) => row.length));
          const result = lines.map((row) => {
            const padding = Array(maxLen - row.length).fill("");
            return [...row, ...padding];
          });
          
          return result;
        },
      },
    ]}>
    Import Users
  </DromoUploader>
  ```
</CodeGroup>
