Express CSV Logo

Quickstart

Use this pre-built prompt to get started faster with Nuxt.

Alternatively, follow these steps to manually add ExpressCSV to a Nuxt app and receive imports in a Nitro server route.

  1. Install the SDK

    npm install @expresscsv/sdk
  2. Get your publishable key

    You need a publishable key from the dashboard to connect the importer.

    New accounts start with two environments: Production and Development. For this example, grab the key from your Development environment.

  3. Create a client component for the importer

    In Nuxt, keep the importer in a client-only component so it only runs in the browser:

    <script setup lang="ts">
    import { CSVImporter, x } from '@expresscsv/sdk';
    import { ref } from 'vue';
    
    const isOpen = ref(false);
    
    const productSchema = x.row({
      sku: x.string().label('SKU'),
      name: x.string().min(1).label('Product Name'),
      price: x.number().min(0).currency('USD').label('Price'),
    });
    
    const importer =
      import.meta.client
        ? new CSVImporter({
            schema: productSchema,
            publishableKey: 'pk_test_...',
            importIdentifier: 'product-import',
            title: 'Import products',
          })
        : null;
    
    function openImporter() {
      if (!importer) {
        return;
      }
    
      isOpen.value = true;
    
      importer.open({
        chunkSize: 500,
        webhook: {
          url: '/api/webhooks/products-import',
          headers: {
            Authorization: 'Bearer your-api-token',
          },
          metadata: {
            userId: 'user-123',
          },
        },
        onComplete: () => {
          isOpen.value = false;
        },
        onCancel: () => {
          isOpen.value = false;
        },
        onError: (error) => {
          isOpen.value = false;
          console.error('Import error', error);
        },
      });
    }
    </script>
    
    <template>
      <button type="button" :disabled="isOpen" @click="openImporter">
        Import Products
      </button>
    </template>
  4. Render the button from a page

    <script setup lang="ts">
    import ImportProductsButton from '~/components/ImportProductsButton.client.vue';
    </script>
    
    <template>
      <ImportProductsButton />
    </template>
  5. Receive webhook deliveries in a Nitro route

    Keep the schema in a shared or server package so both the frontend and the route can import it, then use @expresscsv/schemas to infer the webhook payload:

    import type { InferWebhookPayload } from '@expresscsv/schemas';
    import { productSchema } from '~/server/schema/product-schema';
    
    export default defineEventHandler(async (event) => {
      const token = getHeader(event, 'authorization');
    
      if (token !== 'Bearer your-api-token') {
        setResponseStatus(event, 401);
        return { error: 'Unauthorized' };
      }
    
      const payload =
        await readBody<InferWebhookPayload<typeof productSchema>>(event);
    
      console.log('Received import chunk', payload.records);
    
      return { ok: true };
    });

    Return a 2xx response for each chunk. 5xx and 429 responses are retried automatically, while other 4xx responses are treated as permanent failures.

  6. Optional: disable preloading

    By default, the widget preloads in a hidden iframe so it opens instantly. To show a loading screen instead:

    const importer = new CSVImporter({
      schema: productSchema,
      publishableKey: 'pk_test_...',
      importIdentifier: 'product-import',
      preload: false,
    });

What's Next

  • Types - define field types, validation rules, and TypeScript types
  • Styling - theme the widget to match your app
  • Webhooks - delivery patterns and retry behavior
  • API Reference - full constructor, open(), and lifecycle reference