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:
- Project ID - Found in Project Settings
- Schema ID - Created in the Schemas section
- 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:
| Field | Type | Required |
|---|---|---|
first_name | string | Yes |
last_name | string | Yes |
email | string | Yes |
department | string | No |
hire_date | date | No |
salary | number | No |
Copy the Schema ID after saving.
Generate a Publishable Key
Go to Keys → Create 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:
- employees-valid.csv - Clean data, no errors
- employees-errors.csv - Data with validation errors
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?
- Add validation rules - Define custom validation
- Enable PII masking - Protect sensitive data
- Add transforms - Clean and normalize data
- Sync to your backend - Configure webhooks
- Troubleshooting - Common issues and solutions
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.