# CSVJetty for JavaScript

CSV upload, column mapping, validation, and inline correction inside your app. Receive records in a browser callback or deliver them to a configured webhook.

[Try the demo](https://www.csvjetty.com/demo) · [Watch the importer](https://www.csvjetty.com/ImporterDemo.mp4) · [Configure an importer](https://www.csvjetty.com/dashboard)

## Install

```sh
npm install @csvjetty/js
```

No React dependency. Serve your app over HTTPS or localhost in a modern browser with native dialog support.

## Quick start

Create an importer in the dashboard and copy its public importer key. Add a button with `id="import"` and a `<pre id="records"></pre>` element to your page. This example displays records in memory.

```js
import CSVJetty from "@csvjetty/js";

document.getElementById("import").addEventListener("click", () => {
  CSVJetty.open({
    importerKey: "YOUR_PUBLIC_IMPORTER_KEY",
    onData({ rows }) {
      document.getElementById("records").textContent = JSON.stringify(rows, null, 2);
    },
  });
});
```

### Plain HTML

```html
<button id="import" type="button">Import contacts</button>
<pre id="records"></pre>
<script src="https://cdn.jsdelivr.net/npm/@csvjetty/js@0.1.0/dist/csvjetty.min.js"></script>
<script>
  document.getElementById("import").onclick = function () {
    CSVJetty.open({
      demo: true,
      onData: function ({ rows }) {
        document.getElementById("records").textContent = JSON.stringify(rows, null, 2);
      }
    });
  };
</script>
```

`demo: true` opens the built-in contacts importer without an account. For your own data schema, replace `demo` with your public `importerKey`.

## API

`CSVJetty.open(options)` opens the importer and returns a controller. A named `open` export is also available.

| Option | Purpose |
| --- | --- |
| `importerKey` | Public importer UUID; required unless `demo` is true |
| `demo` | Open the built-in contacts demo; default false |
| `columns` | Optional field definitions and synchronous validators |
| `onData(payload)` | Receive callback records; may return a promise |
| `onComplete(result)` | Receives `{ importId, accepted, rejected }` |
| `onClose()` | Called on normal close |
| `baseUrl` | Service origin; default `https://www.csvjetty.com` |
| `previewToken` | Dashboard preview token; normally omitted |

| Controller method | Behavior |
| --- | --- |
| `close()` | Block while busy; confirm before discarding unsaved changes |
| `destroy()` | Remove the importer immediately without calling `onClose` |
| `updateCallbacks(handlers)` | Replace callback handlers while open |

Call `destroy()` when removing the hosting page or component. It cannot cancel a save already running in your app. Invalid configuration or opening a second importer throws an error.

### Save records

Use `onData` to save records through your authenticated API. Validate records on the server and use `importId` and `rowNumbers` to make retries safe.

Return nothing for success, or `{ errors: [{ row: 2, message: "Email already exists" }] }` for individual failures. Throw or reject the returned promise to report a failed save. For webhook delivery, configure an HTTPS endpoint in the dashboard and omit `onData`.

With callback delivery, CSV row data stays in the browser until your app handles it; CSVJetty receives configuration and import metadata. Webhook delivery sends records through CSVJetty for delivery and retries. Original uploaded files are not stored by CSVJetty.

## Documentation

- [Columns and custom validation](https://www.csvjetty.com/docs/columns)
- [Callback payloads and row errors](https://www.csvjetty.com/docs/callbacks)
- [Signed webhooks](https://www.csvjetty.com/docs/webhooks)
- [Requirements and limits](https://www.csvjetty.com/docs/reference/limits)

## Other integrations

| Framework | Package |
| --- | --- |
| React / Next.js | `csvjetty` |
| JavaScript / HTML | `@csvjetty/js` |
| Vue 3 | `@csvjetty/vue` |
| Angular | `@csvjetty/angular` |

## License

MIT. See [LICENSE](./LICENSE). The SDK license does not cover the hosted CSVJetty service.
