Receipt Extractor with Next JS
Build an AI-powered receipt extraction app with Next.js and JamAI Base
1. Introduction
This comprehensive tutorial will guide you through building a full-stack receipt extraction application using Next.js and the JamAI Base TypeScript SDK. The application uses AI to automatically extract key information from receipt images.
What We'll Build
An AI-powered web application that allows users to:
Upload receipt images through drag-and-drop or file selection
Extract information automatically using JamAI Base Action Tables:
Shop/Store Name
Category (Groceries, Restaurant, Retail, etc.)
Total Amount
View processing history with pagination
Display results in a modern, responsive UI
Key Features
Modern Next.js 16 with App Router and React Server Components
TypeScript for type safety
Tailwind CSS 4 for styling with dark mode support
SWR for efficient data fetching and caching
Real-time Processing with loading states
Responsive Design for mobile and desktop
Image Upload with validation and preview
Prerequisites
Before starting, you'll need:
Node.js 16.x or higher installed
Basic knowledge of React and TypeScript
Project ID and Personal Access Token (PAT) from JamAI Base
A code editor (VS Code recommended)
2. Project Setup
2.1 Create Next.js Project
First, create a new Next.js project with TypeScript:
When prompted, select:
TypeScript: Yes
ESLint: Yes
Tailwind CSS: Yes
src/directory: YesApp Router: Yes
Import alias: Yes (@/*)
2.2 Install Dependencies
Install the required packages:
Dependencies:
jamaibase- JamAI Base TypeScript SDK for AI operationsswr- React hooks for data fetching with caching
2.3 Project Structure
Create the following folder structure:
3. Getting Your Credentials
3.1 Get Your Personal Access Token (PAT)
Click on your username in the top right
Select Account Settings
Navigate to Personal Access Token section
Click Create Personal Access Token
Copy and save your token securely
3.2 Get Your Project ID
In the JamAI Base dashboard, navigate to your project
Look at the browser URL:
https://cloud.jamaibase.com/project/{PROJECT_ID}Copy the Project ID from the URL
3.3 Configure Environment Variables
Create a .env.local file in your project root:
Also create a .env.example file for reference:
Important: Never commit .env.local to version control. Add it to your .gitignore file.
4. Core Configuration
4.1 Create Type Definitions
Create src/lib/types.ts:
4.2 Initialize JamAI Client
Create src/lib/jamai.ts:
Key Points:
Uses singleton pattern for the JamAI client
Validates environment variables on initialization
Automatically creates the Action Table if it doesn't exist
Configures three LLM output columns with specific prompts
Uses Qwen3-VL-30B (embedded LLM) for cost-effective, fast processing
Prompts include table context and use
${Image}variable reference
5. Building the API Routes
5.1 File Upload Route
Create src/app/api/jamai/upload/route.ts:
What this does:
Accepts multipart form data with an image file
Validates file type (images only) and size (10MB max)
Uploads the file to JamAI Base storage
Returns a URI for the uploaded file
5.2 Receipt Processing Route
Create src/app/api/jamai/process/route.ts:
What this does:
Receives the uploaded image URI
Ensures the Action Table exists
Adds a row to the table with the image
JamAI Base automatically processes the image through LLMs
Extracts the AI-generated outputs (shop name, category, total)
Returns the structured receipt data
5.3 History Retrieval Route
Create src/app/api/jamai/history/route.ts:
What this does:
Accepts pagination parameters (offset, limit)
Fetches historical receipts from the Action Table
Unwraps JamAI's nested data structure
Returns paginated results
Handles the case when the table doesn't exist yet
6. Building the UI Components
6.1 Loading Spinner Component
Create src/components/LoadingSpinner.tsx:
6.2 Receipt Upload Component
Create src/components/ReceiptUpload.tsx:
Key Features:
Drag-and-drop file upload
Click to select file
Image preview before processing
Client-side validation
Visual loading states with progress messages
Error handling
6.3 Receipt Results Component
Create src/components/ReceiptResults.tsx:
6.4 Receipt History Component
Create src/components/ReceiptHistory.tsx:
Key Features:
Uses SWR for data fetching with caching
Auto-refreshes when new receipts are added
Responsive design (table on desktop, cards on mobile)
Pagination support
Empty state handling
6.5 Custom Hook for Data Fetching
Create src/hooks/useReceipts.ts:
7. Building the Main Page
7.1 Update Layout
Update src/app/layout.tsx:
7.2 Create Main Page
Update src/app/page.tsx:
8. Running the Application
8.1 Start Development Server
The application will start at http://localhost:3000
8.2 Test the Application
Upload a Receipt
Drag and drop a receipt image, or click to select a file
Supported formats: JPEG, PNG, WebP, GIF (max 10MB)
Process Receipt
Click "Process Receipt" button
Watch the progress indicators:
"Uploading image..."
"Extracting receipt data..."
View Results
See extracted information:
Shop Name
Category
Total Amount
Check History
Scroll down to see all processed receipts
Navigate through pages if you have more than 50 receipts
8.3 First Run
On the first API call, the application will automatically:
Connect to JamAI Base using your credentials
Create the "receipt" Action Table if it doesn't exist
Configure the LLM columns with extraction prompts
Check your terminal logs to see:
9. How It Works
9.1 Architecture Overview
9.2 Data Flow
Upload Phase
User selects/drops an image file
Client validates file type and size
FormData sent to
/api/jamai/uploadImage stored in JamAI Base, returns URI
Processing Phase
Client sends image URI to
/api/jamai/processAPI ensures Action Table exists
Row added to table with image URI
JamAI Base triggers LLM processing:
Qwen3-VL-30B (embedded LLM) analyzes the image
Three separate prompts extract different fields
Results stored in table columns
Display Phase
API returns structured receipt data
Client displays results
History automatically refreshes
9.3 JamAI Base Action Table Structure
The "receipt" table has the following schema:
Image
Input (image)
Receipt image file
Shop Name
LLM Output (str)
Extracted store name
Category
LLM Output (str)
Receipt category
Total
LLM Output (str)
Total amount with currency
Each LLM Output column has:
Model: ellm/Qwen/Qwen3-VL-30B-A3B-Instruct (embedded vision LLM)
Temperature: 0.1 (for consistency)
Custom Prompts: Specialized for each field with table context and variable references
10. Customization
10.1 Modify Extraction Prompts
To change what information is extracted, edit the prompts in src/lib/jamai.ts:
10.2 Add New Fields
To extract additional information:
Add the column definition in
ensureTableExists():
Update the
Receiptinterface in src/lib/types.ts:
Update extraction in the process route
Update UI components to display the new field
10.3 Change LLM Model
You can use different models for different accuracy and cost trade-offs:
Note: When using different models, remember to include proper context in prompts. For vision models, use the ${Image} variable reference as shown in the examples.
10.4 Styling Customization
The app uses Tailwind CSS. Customize colors, spacing, and styles:
11. Deployment
11.1 Deploy to Vercel
Push to GitHub
Deploy on Vercel
Go to vercel.com
Click "Import Project"
Select your GitHub repository
Add environment variables:
JAMAI_API_KEYJAMAI_PROJECT_ID
Click "Deploy"
Verify Deployment
Visit your deployment URL
Test receipt upload and processing
11.2 Environment Variables in Production
Never commit your .env.local file. Always set environment variables in your deployment platform's dashboard.
12. Troubleshooting
Common Issues
Issue: "Missing JamAI credentials" error
Solution:
Verify
.env.localexists in project rootCheck that variables are named correctly:
JAMAI_API_KEY(notJAMAI_TOKEN)JAMAI_PROJECT_ID(notPROJECT_ID)
Restart development server after adding env variables
Issue: Upload fails with "File too large"
Solution:
Ensure image is under 10MB
Compress image before uploading
Or increase
MAX_FILE_SIZEin src/app/api/jamai/upload/route.ts
Issue: Processing takes too long
Solution:
This is normal for first request (table creation)
Subsequent requests are faster
Consider using concurrent: true for background processing
Issue: Extraction accuracy is poor
Solution:
Use higher quality images (clear, well-lit receipts)
Try different vision models (e.g., openai/gpt-4o for better accuracy)
Refine prompts to be more specific
Ensure prompts include proper table context and variable references like
${Image}Adjust temperature slightly (lower for consistency, higher for variety)
Issue: History not refreshing
Solution:
Check browser console for errors
Verify
refreshTriggeris incrementingClear browser cache
Check API route returns valid data
13. Best Practices
Security
Protect API Keys
Never commit
.env.localUse environment variables in production
Rotate API keys periodically
Validate Input
Always validate file types and sizes
Sanitize user inputs
Implement rate limiting for production
Error Handling
Never expose sensitive error details to users
Log errors server-side
Provide user-friendly error messages
Performance
Optimize Images
Compress images before upload
Consider image optimization libraries
Caching
SWR handles client-side caching
Consider server-side caching for frequently accessed data
Concurrent Processing
For bulk uploads, use
concurrent: trueinaddRow()Implement queue system for large batches
Code Quality
TypeScript
Define interfaces for all data structures
Avoid
anytypesUse strict mode
Components
Keep components focused and reusable
Extract common logic into hooks
Use proper TypeScript types for props
Testing
Add unit tests for utility functions
Test API routes
Implement E2E tests for critical flows
14. Next Steps
Enhancements to Try
Multi-file Upload
Process multiple receipts at once
Show progress for batch processing
Export Functionality
Export history to CSV
Generate expense reports
Integration with accounting software
Advanced Features
Receipt search and filtering
Date range selection
Analytics dashboard
Monthly/yearly summaries
Mobile App
Build React Native app
Use device camera for capture
Offline support with sync
Authentication
Add user accounts
Personal receipt history
Multi-user support
15. Resources
16. Support
If you encounter issues or have questions:
Check the JamAI Base Documentation
Review this tutorial's troubleshooting section
Contact JamAI Base support
Conclusion
You've successfully built a full-stack receipt extraction application using:
Next.js 16 with App Router
JamAI Base for AI-powered data extraction
TypeScript for type safety
Tailwind CSS for modern UI
SWR for efficient data fetching
The application demonstrates how easy it is to integrate AI capabilities into web applications using JamAI Base Action Tables. You can now extend this foundation to build more complex document processing applications.
Happy building!
Last updated
Was this helpful?