---
title: HTTP Downloads
pagination_next: demos/net/upload/index
---

<head>
  <script src="https://unpkg.com/axios@1.6.5/dist/axios.min.js"></script>
  <script src="https://unpkg.com/superagent@8.1.2/dist/superagent.min.js"></script>
</head>

import current from '/version.js';
import CodeBlock from '@theme/CodeBlock';

[SheetJS](https://sheetjs.com) is a JavaScript library for reading and writing
data from spreadsheets.

A number of JavaScript APIs, including `XMLHttpRequest` and `fetch`, allow
scripts to download spreadsheets for further processing.

This demo uses various APIs and wrapper libraries to download workbooks and pass
raw binary data to SheetJS libraries.

- ["Browser Demos"](#browser-demos) run entirely within the web browser. A test
  workbook will be downloaded and parsed in the web browser.

- ["NodeJS Demos"](#nodejs-demos) run in NodeJS and other server-side platforms.

:::info pass

This demo focuses on downloading files. Other demos cover other HTTP use cases:

- ["HTTP Uploads"](/docs/demos/net/upload) covers uploading files
- ["HTTP Server Processing"](/docs/demos/net/server) covers HTTP servers

:::

:::caution Third-Party Hosts and Binary Data

Third-party cloud platforms such as AWS may corrupt raw binary downloads by
encoding requests and responses in UTF-8 strings.

For AWS, in the "Binary Media Types" section of the API Gateway console, the
`"application/vnd.ms-excel"` type should be added to ensure that AWS Lambda
functions functions can send files to clients.

:::

## Binary Data

Most interesting spreadsheet files are binary data that contain byte sequences
that represent invalid UTF-8 characters.

APIs generally provide options to control how downloaded data is interpreted.
The `arraybuffer` response type usually forces the data to be presented as an
`ArrayBuffer` object which can be parsed with the SheetJS `read` method[^1].

The following example shows the data flow using `fetch` to download files:

```mermaid
flowchart LR
  server[(Remote\nFile)]
  response(Response\nobject)
  subgraph SheetJS operations
    ab(XLSX Data\nArrayBuffer)
    wb(((SheetJS\nWorkbook)))
  end
  server --> |`fetch`\nGET request| response
  response --> |`arrayBuffer`\n\n| ab
  ab --> |`read`\n\n| wb
```

```js
/* download data into an ArrayBuffer object */
const res = await fetch("https://docs.sheetjs.com/pres.numbers");
const ab = await res.arrayBuffer(); // recover data as ArrayBuffer

/* parse file */
const wb = XLSX.read(ab);
```

## Browser Demos

When the page is accessed, https://docs.sheetjs.com/pres.numbers will be fetched
and parsed. The old table will be replaced with a table whose contents match the
first worksheet. The SheetJS `sheet_to_html` method[^2] creates the HTML table.

:::note Tested Deployments

Each browser demo was tested in the following environments:

| Browser     | Date       |
|:------------|:-----------|
| Chrome 133  | 2025-03-30 |
| Safari 18.3 | 2025-03-30 |

:::

### XMLHttpRequest

For downloading data, the `arraybuffer` response type generates an `ArrayBuffer`
that can be viewed as an `Uint8Array` and fed to the SheetJS `read` method. For
legacy browsers, the option `type: "array"` should be specified:

```js
/* set up an async GET request */
var req = new XMLHttpRequest();
req.open("GET", url, true);
req.responseType = "arraybuffer";

req.onload = function(e) {
  /* parse the data when it is received */
  var data = new Uint8Array(req.response);
  var workbook = XLSX.read(data, {type:"array"});
  /* DO SOMETHING WITH workbook HERE */
};
req.send();
```

<details>
  <summary><b>Live Download demo</b> (click to show)</summary>

This demo uses `XMLHttpRequest` to fetch https://docs.sheetjs.com/pres.numbers
and show the data in an HTML table.

```jsx live
function SheetJSXHRDL() {
  const [__html, setHTML] = React.useState("");

  /* Fetch and update HTML */
  React.useEffect(() => { (async() => {
    /* Fetch file */
    const req = new XMLHttpRequest();
    req.open("GET", "https://docs.sheetjs.com/pres.numbers", true);
    req.responseType = "arraybuffer";
    req.onload = e => {
      /* Parse file */
      const wb = XLSX.read(new Uint8Array(req.response));
      const ws = wb.Sheets[wb.SheetNames[0]];

      /* Generate HTML */
      setHTML(XLSX.utils.sheet_to_html(ws));
    };
    req.send();
  })(); }, []);

  return ( <div dangerouslySetInnerHTML={{ __html }}/> );
}
```

</details>


### fetch

For downloading data, `Response#arrayBuffer` resolves to an `ArrayBuffer` that
can be converted to `Uint8Array` and passed to the SheetJS `read` method:

```js
fetch(url).then(function(res) {
  /* get the data as a Blob */
  if(!res.ok) throw new Error("fetch failed");
  return res.arrayBuffer();
}).then(function(ab) {
  /* parse the data when it is received */
  var data = new Uint8Array(ab);
  var workbook = XLSX.read(data, {type:"array"});

  /* DO SOMETHING WITH workbook HERE */
});
```

<details>
  <summary><b>Live Download demo</b> (click to show)</summary>

This demo uses `fetch` to download https://docs.sheetjs.com/pres.numbers and
show the data in an HTML table.

```jsx live
function SheetJSFetchDL() {
  const [__html, setHTML] = React.useState("");

  /* Fetch and update HTML */
  React.useEffect(() => { (async() => {
    /* Fetch file */
    const res = await fetch("https://docs.sheetjs.com/pres.numbers");
    const ab = await res.arrayBuffer();

    /* Parse file */
    const wb = XLSX.read(ab);
    const ws = wb.Sheets[wb.SheetNames[0]];

    /* Generate HTML */
    setHTML(XLSX.utils.sheet_to_html(ws));
  })(); }, []);

  return ( <div dangerouslySetInnerHTML={{ __html }}/> );
}
```

</details>

### jQuery

[jQuery](https://jquery.com/) is a JavaScript library that includes helpers for
performing "Ajax" network requests. `jQuery.ajax` (`$.ajax`) does not support
binary data out of the box[^3]. A custom `ajaxTransport` can add support.

SheetJS users have reported success with `jquery.binarytransport.js`[^4] in IE10.

After including the main `jquery.js` and `jquery.binarytransport.js` scripts,
`$.ajax` will support `dataType: "binary"` and `processData: false`.

**[Live Download Demo](pathname:///jquery/index.html)**

In a GET request, the default behavior is to return a `Blob` object.  Passing
`responseType: "arraybuffer"` returns a proper `ArrayBuffer` object in IE10:

```js
$.ajax({
  type: "GET", url: "https://docs.sheetjs.com/pres.numbers",

  /* suppress jQuery post-processing */
  // highlight-next-line
  processData: false,

  /* use the binary transport */
  // highlight-next-line
  dataType: "binary",

  /* pass an ArrayBuffer in the callback */
  // highlight-next-line
  responseType: "arraybuffer",

  success: function (ab) {
    /* at this point, ab is an ArrayBuffer */
    // highlight-next-line
    var wb = XLSX.read(ab);

    /* do something with workbook here */
    var ws = wb.Sheets[wb.SheetNames[0]];
    var html = XLSX.utils.sheet_to_html(ws);
    $("#out").html(html);
  }
});
```

### Wrapper Libraries

Before `fetch` shipped with browsers, there were various wrapper libraries to
simplify `XMLHttpRequest`. Due to limitations with `fetch`, these libraries are
still relevant.

#### axios

[`axios`](https://axios-http.com/) presents a Promise based interface. Setting
`responseType` to `arraybuffer` ensures the return type is an ArrayBuffer. The
`data` property of the result can be passed to the SheetJS `read` method:

```js
async function workbook_dl_axios(url) {
  const res = await axios(url, {responseType:'arraybuffer'});
  const workbook = XLSX.read(res.data);
  return workbook;
}
```

<details>
  <summary><b>Live Download demo</b> (click to show)</summary>

This demo uses `axios` to download https://docs.sheetjs.com/pres.numbers and
show the data in an HTML table.

:::caution pass

If the live demo shows a message

```
ReferenceError: axios is not defined
```

please refresh the page.  This is a known bug in the documentation generator.

:::

```jsx live
function SheetJSAxiosDL() {
  const [__html, setHTML] = React.useState("");

  /* Fetch and update HTML */
  React.useEffect(() => { (async() => {
    if(typeof axios != "function") return setHTML("ReferenceError: axios is not defined");
    /* Fetch file */
    const res = await axios("https://docs.sheetjs.com/pres.numbers", {responseType: "arraybuffer"});

    /* Parse file */
    const wb = XLSX.read(res.data);
    const ws = wb.Sheets[wb.SheetNames[0]];

    /* Generate HTML */
    setHTML(XLSX.utils.sheet_to_html(ws));
  })(); }, []);

  return ( <div dangerouslySetInnerHTML={{ __html }}/> );
}
```

</details>

#### superagent

[`superagent`](https://ladjs.github.io/superagent/) is a network request library
with a "Fluent Interface". Calling the `responseType` method with
`"arraybuffer"` will ensure the final response object is an `ArrayBuffer`:

```js
/* set up an async GET request with superagent */
superagent
  .get(url)
  .responseType('arraybuffer')
  .end(function(err, res) {
    /* parse the data when it is received */
    var data = new Uint8Array(res.body);
    var workbook = XLSX.read(data, {type:"array"});

    /* DO SOMETHING WITH workbook HERE */
  });
```

<details>
  <summary><b>Live Download demo</b> (click to show)</summary>

This demo uses `superagent` to download https://docs.sheetjs.com/pres.numbers
and show the data in an HTML table.

:::caution pass

If the live demo shows a message

```
ReferenceError: superagent is not defined
```

please refresh the page.  This is a known bug in the documentation generator.

:::

```jsx live
function SheetJSSuperAgentDL() {
  const [__html, setHTML] = React.useState("");

  /* Fetch and update HTML */
  React.useEffect(() => { (async() => {
    if(typeof superagent == "undefined" || typeof superagent.get != "function")
      return setHTML("ReferenceError: superagent is not defined");
    /* Fetch file */
    superagent
      .get("https://docs.sheetjs.com/pres.numbers")
      .responseType("arraybuffer")
      .end((err, res) => {
        /* Parse file */
        const wb = XLSX.read(res.body);
        const ws = wb.Sheets[wb.SheetNames[0]];

        /* Generate HTML */
        setHTML(XLSX.utils.sheet_to_html(ws));
      });
  })(); }, []);

  return ( <div dangerouslySetInnerHTML={{ __html }}/> );
}
```

</details>

## NodeJS Demos

These examples show how to download data in NodeJS.

### HTTPS GET

The `https` module provides a low-level `get` method for HTTPS GET requests:

```js title="SheetJSHTTPSGet.js"
var https = require("https"), XLSX = require("xlsx");

https.get('https://docs.sheetjs.com/pres.xlsx', function(res) {
  var bufs = [];
  res.on('data', function(chunk) { bufs.push(chunk); });
  res.on('end', function() {
    var buf = Buffer.concat(bufs);
    var wb = XLSX.read(buf);
    /* print the first worksheet to console */
    var ws = wb.Sheets[wb.SheetNames[0]];
    console.log(XLSX.utils.sheet_to_csv(ws));
  });
});
```

:::note Tested Deployments

This demo was tested in the following environments:

| NodeJS     | Date       | Workarounds                    |
|:-----------|:-----------|:-------------------------------|
| `0.10.48`  | 2024-06-21 | `NODE_TLS_REJECT_UNAUTHORIZED` |
| `0.12.18`  | 2024-06-21 | `NODE_TLS_REJECT_UNAUTHORIZED` |
| `4.9.1`    | 2024-06-21 | `NODE_TLS_REJECT_UNAUTHORIZED` |
| `6.17.1`   | 2024-06-21 | `NODE_TLS_REJECT_UNAUTHORIZED` |
| `8.17.0`   | 2024-06-21 | `NODE_TLS_REJECT_UNAUTHORIZED` |
| `10.24.1`  | 2024-06-21 |                                |
| `12.22.12` | 2024-06-21 |                                |
| `14.21.3`  | 2024-06-21 |                                |
| `16.20.2`  | 2024-06-21 |                                |
| `18.20.8`  | 2025-03-30 |                                |
| `20.18.0`  | 2025-03-30 |                                |
| `22.14.0`  | 2025-03-30 |                                |

The `NODE_TLS_REJECT_UNAUTHORIZED` workaround sets the value to `'0'`:

```js title="Legacy NodeJS Certificate has Expired Bypass (prepend to script)"
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
```

:::

<details>
  <summary><b>Complete Example</b> (click to show)</summary>

1) Install the [NodeJS module](/docs/getting-started/installation/nodejs)

<CodeBlock language="bash">{`\
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
</CodeBlock>

2) Copy the `SheetJSHTTPSGet.js` code snippet to a file `SheetJSHTTPSGet.js`

3) Run the script:

```bash
node SheetJSHTTPSGet.js
```

If successful, the script will print CSV contents of the test file.

:::caution pass

For older versions of NodeJS, the script will fail due to a certificate error.
The error can be suppressed by prepending the following line to the script:

```js title="SheetJSHTTPSGet.js (add to top)"
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
```

**It is strongly encouraged to upgrade to a newer NodeJS version!**

:::

</details>

### fetch

:::info pass

Experimental support for `fetch` was introduced in NodeJS `16.15.0`. It will be
considered stable in NodeJS LTS version `22`.

:::

The `fetch` implementation has the same return types as the browser version:

```js
async function parse_from_url(url) {
  const res = await fetch(url);
  if(!res.ok) throw new Error("fetch failed");
  const ab = await res.arrayBuffer();
  const workbook = XLSX.read(ab);
  return workbook;
}
```

:::note Tested Deployments

This demo was tested in the following environments:

| NodeJS     | Date       |
|:-----------|:-----------|
| `18.20.8`  | 2025-03-30 |
| `20.18.0`  | 2025-03-30 |
| `22.14.0`  | 2025-03-30 |

:::

<details>
  <summary><b>Complete Example</b> (click to show)</summary>

1) Install the [NodeJS module](/docs/getting-started/installation/nodejs)

<CodeBlock language="bash">{`\
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
</CodeBlock>

2) Save the following to `SheetJSFetch.js`:

```js title="SheetJSFetch.js"
var XLSX = require("xlsx");

async function parse_from_url(url) {
  const res = await fetch(url);
  if(!res.ok) throw new Error("fetch failed");
  const ab = await res.arrayBuffer();
  const workbook = XLSX.read(ab);
  return workbook;
}

(async() => {
  const wb = await parse_from_url('https://docs.sheetjs.com/pres.numbers');
  /* print the first worksheet to console */
  var ws = wb.Sheets[wb.SheetNames[0]];
  console.log(XLSX.utils.sheet_to_csv(ws));
})();
```

3) Run the script:

```bash
node SheetJSFetch.js
```

If successful, the script will print CSV contents of the test file.

</details>

### Wrapper Libraries

The latest releases of NodeJS support `fetch` natively.  Before `fetch` support
was added to the platform, third party modules wrapped the native APIs.

#### request

:::danger pass

`request` has been deprecated and should only be used in legacy deployments.

:::

Setting the option `encoding: null` passes raw buffers:

```js title="SheetJSRequest.js"
var XLSX = require('xlsx'), request = require('request');
var url = 'https://docs.sheetjs.com/pres.xlsx';

/* call `request` with the option `encoding: null` */
// highlight-next-line
request(url, {encoding: null}, function(err, res, data) {
  if(err || res.statusCode !== 200) return;

  /* if the request was successful, parse the data */
  // highlight-next-line
  var wb = XLSX.read(data);

  /* print the first worksheet to console */
  var ws = wb.Sheets[wb.SheetNames[0]];
  console.log(XLSX.utils.sheet_to_csv(ws));
});
```

:::note Tested Deployments

This demo was tested in the following environments:

| NodeJS     | Date       | Workarounds                    |
|:-----------|:-----------|:-------------------------------|
| `0.10.48`  | 2024-06-21 | `NODE_TLS_REJECT_UNAUTHORIZED` |
| `0.12.18`  | 2024-06-21 | `NODE_TLS_REJECT_UNAUTHORIZED` |
| `4.9.1`    | 2024-06-21 | `NODE_TLS_REJECT_UNAUTHORIZED` |
| `6.17.1`   | 2024-06-21 | `NODE_TLS_REJECT_UNAUTHORIZED` |
| `8.17.0`   | 2024-06-21 | `NODE_TLS_REJECT_UNAUTHORIZED` |
| `10.24.1`  | 2024-06-21 |                                |
| `12.22.12` | 2024-06-21 |                                |
| `14.21.3`  | 2024-06-21 |                                |
| `16.20.2`  | 2024-06-21 |                                |
| `18.20.8`  | 2025-03-30 |                                |
| `20.18.0`  | 2025-03-30 |                                |
| `22.14.0`  | 2025-03-30 |                                |

The `NODE_TLS_REJECT_UNAUTHORIZED` workaround sets the value to `'0'`:

```js title="Legacy NodeJS Certificate has Expired Bypass (prepend to script)"
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
```

:::

<details>
  <summary><b>Complete Example</b> (click to show)</summary>

1) Install the [NodeJS module](/docs/getting-started/installation/nodejs)

<CodeBlock language="bash">{`\
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz request@2.88.2`}
</CodeBlock>

2) Copy the `SheetJSRequest.js` code snippet to a file `SheetJSRequest.js`

3) Run the script:

```bash
node SheetJSRequest.js
```

If successful, the script will print CSV contents of the test file.

:::caution pass

For older versions of NodeJS, the script will fail due to a certificate error.
The error can be suppressed by prepending the following line to the script:

```js title="SheetJSRequest.js (add to top)"
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
```

**It is strongly encouraged to upgrade to a newer NodeJS version!**

:::

</details>

#### axios

When the `responseType` is `"arraybuffer"`, `axios` actually captures the data
in a NodeJS Buffer. The SheetJS `read` method handles NodeJS Buffer objects:

```js title="SheetJSAxios.js"
const XLSX = require("xlsx"), axios = require("axios");

async function workbook_dl_axios(url) {
  const res = await axios(url, {responseType:'arraybuffer'});
  /* at this point, res.data is a Buffer */
  const workbook = XLSX.read(res.data);
  return workbook;
}
```

:::note Tested Deployments

This demo was tested in the following environments:

| NodeJS     | Axios  | Date       |
|:-----------|:-------|:-----------|
| `10.24.1`  | 0.28.1 | 2024-06-21 |
| `12.22.12` | 1.7.2  | 2024-06-21 |
| `14.21.3`  | 1.7.2  | 2024-06-21 |
| `16.20.2`  | 1.7.2  | 2024-06-21 |
| `18.20.8`  | 1.8.4  | 2025-03-30 |
| `20.18.0`  | 1.8.4  | 2025-03-30 |
| `22.14.0`  | 1.8.4  | 2025-03-30 |

:::

<details>
  <summary><b>Complete Example</b> (click to show)</summary>

1) Install the [NodeJS module](/docs/getting-started/installation/nodejs)

<CodeBlock language="bash">{`\
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz axios@1.8.4`}
</CodeBlock>

2) Save the following to `SheetJSAxios.js`:

```js title="SheetJSAxios.js"
const XLSX = require("xlsx"), axios = require("axios");

async function workbook_dl_axios(url) {
  const res = await axios(url, {responseType:'arraybuffer'});
  /* at this point, res.data is a Buffer */
  const workbook = XLSX.read(res.data);
  return workbook;
}

(async() => {
  const wb = await workbook_dl_axios('https://docs.sheetjs.com/pres.numbers');
  /* print the first worksheet to console */
  var ws = wb.Sheets[wb.SheetNames[0]];
  console.log(XLSX.utils.sheet_to_csv(ws));
})();
```

3) Run the script:

```bash
node SheetJSAxios.js
```

If successful, the script will print CSV contents of the test file.

</details>

## Other Platforms

Other demos show network operations in special platforms:

- [React Native "Fetching Remote Data"](/docs/demos/mobile/reactnative#fetching-remote-data)
- [NativeScript "Fetching Remote Files"](/docs/demos/mobile/nativescript#fetching-remote-files)
- [AngularJS "Remote Files"](/docs/demos/frontend/angularjs#remote-files)
- [Dojo Toolkit "Parsing Remote Files"](/docs/demos/frontend/dojo#parsing-remote-files)

[^1]: See [`read` in "Reading Files"](/docs/api/parse-options)
[^2]: See [`sheet_to_html` in "Utilities"](/docs/api/utilities/html#html-table-output)
[^3]: See [`dataType` in `jQuery.ajax`](https://api.jquery.com/jQuery.ajax/) in the official jQuery documentation.
[^4]: See [the official `jquery.binarytransport.js` repo](https://github.com/henrya/js-jquery/tree/master/BinaryTransport) for more details.
