Skip to main content

React Quickstart

This guide gets you from zero to a working CSV importer in your React app.

Time required: 5 minutes

Prerequisites:

  • React 18+ application
  • Node.js 18+
  • An RowOps account (sign up at app.rowops.dev)

Step 1: Install the Package

npm install @rowops/importer

Or with other package managers:

# Yarn
yarn add @rowops/importer

# pnpm
pnpm add @rowops/importer

Step 2: Get Your Credentials

You need three things from the RowOps dashboard:

  1. Project ID - Found in Project Settings
  2. Schema ID - Created in the Schemas section
  3. Publishable Key - Generated in the Keys section

Create a Schema

In the dashboard, go to Schemas and create a new schema. Here's an example for employee data:

FieldTypeRequired
first_namestringYes
last_namestringYes
emailstringYes
departmentstringNo
hire_datedateNo
salarynumberNo

Copy the Schema ID after saving.

Generate a Publishable Key

Go to KeysCreate Key → Select Publishable type.

Copy the key (starts with pk_).

Add Your Domain

Go to Domains and add your production domain. localhost is allowed by default for development.


Step 3: Add the Importer Component

import { RowOpsImporter } from "@rowops/importer";

export default function ImportPage() {
const handleComplete = (result) => {
console.log("Import complete!", result);
console.log(`Imported ${result.totalRows} rows`);
};

return (
<RowOpsImporter
projectId="proj_your_project_id"
schemaId="your_schema_id"
publishableKey="pk_live_your_key"
onComplete={handleComplete}
/>
);
}

That's it! You now have a working CSV importer.


Step 4: Handle the Imported Data

The onComplete callback receives an ImportResult object:

interface ImportResult {
datasetRef: string; // Reference to the dataset
datasetNonce: number; // Unique import session ID
totalRows: number; // Total rows imported
runMeta: { // Runtime identity for the import run
importRunId: string;
importSessionId?: string;
datasetRef?: string;
datasetNonce?: string;
};
summary?: {
totalRows: number;
validRows: number;
invalidRows: number;
};
}

Option A: Streaming Mode (Large Files)

For large files, stream data in chunks to avoid memory issues:

<RowOpsImporter
projectId="proj_123"
schemaId="employees"
publishableKey="pk_live_..."
onExportChunk={async (chunk, progress) => {
console.log(`Processing chunk: ${progress.current}/${progress.total}`);

// Upload each chunk to your backend
await fetch("/api/import/chunk", {
method: "POST",
body: JSON.stringify(chunk),
});
}}
onExportComplete={(summary) => {
console.log(`Done! Imported ${summary.totalRows} rows`);
}}
/>

Option B: Arrow IPC Streaming (Maximum Performance)

For zero-copy, maximum performance with large datasets:

<RowOpsImporter
projectId="proj_123"
schemaId="employees"
publishableKey="pk_live_..."
onExportIpcChunk={async (bytes, chunkIndex) => {
// bytes is a Uint8Array in Arrow IPC format
// Upload directly to your backend
await fetch(`/api/import/ipc/${chunkIndex}`, {
method: "POST",
body: bytes,
headers: { "Content-Type": "application/vnd.apache.arrow.stream" },
});
}}
onExportComplete={(summary) => {
console.log(`Done! ${summary.totalChunks} chunks, ${summary.totalRows} rows`);
}}
/>

Step 5: Test with Sample Data

Download our sample CSV to test your integration:


Complete Example

Here's a full example with error handling:

import { RowOpsImporter } from "@rowops/importer";
import { useState } from "react";

export default function ImportPage() {
const [importResult, setImportResult] = useState(null);
const [error, setError] = useState(null);

return (
<div>
<h1>Import Employees</h1>

<RowOpsImporter
projectId={process.env.NEXT_PUBLIC_ROWOPS_PROJECT_ID}
schemaId="employees"
publishableKey={process.env.NEXT_PUBLIC_ROWOPS_KEY}
onComplete={(result) => {
setImportResult(result);
setError(null);
console.log(`Imported ${result.totalRows} employees`);
}}
/>

{importResult && (
<div>
<h2>Import Complete</h2>
<p>Total rows: {importResult.totalRows}</p>
<p>Valid rows: {importResult.summary?.validRows}</p>
<p>Invalid rows: {importResult.summary?.invalidRows}</p>
</div>
)}
</div>
);
}

Framework-Specific Notes

Next.js (App Router)

The importer is a client component. Mark your page with "use client":

"use client";

import { RowOpsImporter } from "@rowops/importer";

export default function Page() {
return <RowOpsImporter {...props} />;
}

Next.js (Pages Router)

Import dynamically to avoid SSR issues:

import dynamic from "next/dynamic";

const RowOpsImporter = dynamic(
() => import("@rowops/importer").then((m) => m.RowOpsImporter),
{ ssr: false }
);

export default function Page() {
return <RowOpsImporter {...props} />;
}

Vite

Works out of the box. No special configuration needed.

Create React App

Works out of the box. No special configuration needed.


Environment Variables

Store your credentials in environment variables:

# .env.local (Next.js) or .env (Vite/CRA)
NEXT_PUBLIC_ROWOPS_PROJECT_ID=proj_123
NEXT_PUBLIC_ROWOPS_SCHEMA_ID=employees
NEXT_PUBLIC_ROWOPS_KEY=pk_live_xxx
<RowOpsImporter
projectId={process.env.NEXT_PUBLIC_ROWOPS_PROJECT_ID}
schemaId={process.env.NEXT_PUBLIC_ROWOPS_SCHEMA_ID}
publishableKey={process.env.NEXT_PUBLIC_ROWOPS_KEY}
onComplete={handleComplete}
/>

Theming

The importer supports light and dark modes. Wrap with ThemeProvider:

import { RowOpsImporter, ThemeProvider } from "@rowops/importer";

export default function App() {
return (
<ThemeProvider attribute="class" defaultTheme="system" enableSystem>
<RowOpsImporter {...props} />
</ThemeProvider>
);
}

What's Next?


Troubleshooting

"Domain not authorized"

Add your domain in Dashboard → Project → Domains. localhost is always allowed.

"Schema not found"

Verify schemaId matches a schema in your project. Schema IDs are case-sensitive.

"Invalid publishable key"

Check that the key starts with pk_ and hasn't been revoked.

Importer doesn't render

Ensure you're not rendering on the server. Use dynamic import with { ssr: false } in Next.js.

Data not appearing in onComplete

Make sure the user completes the full import flow (upload → map → validate → export).

For more issues, see the Error Codes Reference.