File Upload Setup Guide

Enable users to upload images, documents, and files to your AI agents for processing.

File Upload Overview

What Can Users Upload?

Supported File Types:

  • 📷 Images: .jpg, .jpeg, .png, .gif
  • 📄 Documents: .pdf, .doc, .docx
  • 📊 Spreadsheets: .xls, .xlsx

File Limits:

  • Per File: 25MB maximum
  • Total Upload: 100MB maximum per submission
  • Multiple Files: Yes, upload several files at once

How It Works

1. User drags/selects files
   ↓
2. Preview shows thumbnails
   ↓
3. JavaScript validates (size, type)
   ↓
4. On submit: Files converted to base64
   ↓
5. Sent to webhook with metadata
   ↓
6. Webhook processes files
   ↓
7. Response sent back to user

Adding File Upload to Forms

Step 1: Create File Upload Field

  1. Edit your AI Agent
  2. Scroll to Form Builder
  3. Click "Add Field"
  4. Configure:
Label: "Upload Your Image"
Field Type: File
Accept: image/png,image/jpeg,image/jpg,image/gif
Required: No (or Yes if mandatory)
Help Text: "Upload an image for AI processing (Max 25MB)"

Step 2: Configure Accepted Types

Images Only:

Accept: image/*

Documents Only:

Accept: .pdf,.doc,.docx

Spreadsheets:

Accept: .xls,.xlsx

Multiple Types:

Accept: image/*,.pdf,.doc,.docx

Everything Allowed:

Accept: (leave empty)

Step 3: Save & Test

  1. Click "Save Form"
  2. View agent on frontend
  3. Test drag & drop
  4. Test file selection

File Upload Features

Drag & Drop Interface

Users can:

  • 🖱️ Click to browse - Traditional file picker
  • 🎯 Drag files - Drag files onto upload area
  • 👁️ Preview - See thumbnails before uploading
  • Remove files - Click X to remove unwanted files
  • 📂 Multiple files - Upload several at once

Visual Feedback

Upload Area States:

1. Empty (Ready):

┌─────────────────────────────┐
│      📁                      │
│  Click or drag files here   │
│  Max 25MB per file, 100MB   │
│  total                       │
└─────────────────────────────┘

2. Drag Over (Active):

┌═════════════════════════════┐
║      📁 ⬇️                   ║
║   Drop your files here!     ║
║                             ║
║                             ║
└═════════════════════════════┘

3. Files Selected (Preview):

┌─────────────────────────────┐
│ ┌───┐ photo1.jpg    ❌      │
│ │img│ 1.2 MB                │
│ └───┘                        │
│                              │
│ ┌───┐ photo2.jpg    ❌      │
│ │img│ 850 KB                │
│ └───┘                        │
│                              │
│ [+] Add more files           │
└─────────────────────────────┘

Image Previews

  • For images: Shows actual thumbnail
  • For PDFs: Shows 📄 icon + filename
  • For Word docs: Shows 📝 icon + filename
  • For Excel: Shows 📊 icon + filename

File Information Display

Each file shows:

  • ✅ Filename
  • ✅ File size (formatted: KB, MB)
  • ✅ Visual preview (for images)
  • ✅ Remove button (X)

Processing Uploaded Files

File Data Structure

When a file is uploaded, WordPress sends this data to your webhook:

{
  "form_data": {
    "field_image_file_data": "iVBORw0KGgoAAAANSUhEUgAA...",
    "field_image_file_name": "photo.jpg",
    "field_image_file_type": "image/jpeg",
    "field_image_file_size": 245678
  }
}

Data Fields:

  • *_file_data - Base64 encoded file content
  • *_file_name - Original filename
  • *_file_type - MIME type
  • *_file_size - Size in bytes

n8n: Decode and Use Files

Method 1: Convert to Binary (Images/PDFs)

// In n8n Code node
const fileData = $json.body.form_data.field_image_file_data;
const fileName = $json.body.form_data.field_image_file_name;
const fileType = $json.body.form_data.field_image_file_type;

// Decode base64 to buffer
const buffer = Buffer.from(fileData, 'base64');

return {
  binary: {
    data: buffer,
    fileName: fileName,
    mimeType: fileType
  }
};

Method 2: Save to Temporary File

const fs = require('fs');
const path = require('path');

const fileData = $json.body.form_data.field_image_file_data;
const fileName = $json.body.form_data.field_image_file_name;

// Decode and save
const buffer = Buffer.from(fileData, 'base64');
const tempPath = path.join('/tmp', fileName);
fs.writeFileSync(tempPath, buffer);

return {
  filePath: tempPath,
  fileName: fileName,
  saved: true
};

Method 3: Upload to Cloud Storage

Upload to AWS S3:

const AWS = require('aws-sdk');
const s3 = new AWS.S3({
  accessKeyId: 'YOUR_ACCESS_KEY',
  secretAccessKey: 'YOUR_SECRET_KEY'
});

const fileData = $json.body.form_data.field_image_file_data;
const fileName = $json.body.form_data.field_image_file_name;
const buffer = Buffer.from(fileData, 'base64');

const params = {
  Bucket: 'your-bucket-name',
  Key: `uploads/${Date.now()}-${fileName}`,
  Body: buffer,
  ContentType: $json.body.form_data.field_image_file_type
};

const result = await s3.upload(params).promise();

return {
  url: result.Location,
  bucket: result.Bucket,
  key: result.Key
};

Use Cases & Examples

Use Case 1: AI Image Enhancement

Scenario: User uploads photo, AI enhances it

Form Fields:

  • File upload (image)
  • Enhancement type (select: Upscale, Denoise, Colorize)
  • Email for results

n8n Workflow:

[Webhook]
   ↓
[Code: Decode image]
   ↓
[HTTP Request: Upload to Replicate]
   ↓
[Replicate: Enhance image]
   ↓
[Code: Get result URL]
   ↓
[Respond with enhanced image]

Response:

return {
  output_html: `
    <div class="enhancement-result">
      <h3>✨ Enhanced Image Ready!</h3>
      <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 20px;">
        <div>
          <h4>Original</h4>
          <img src="${originalUrl}" style="max-width: 100%">
        </div>
        <div>
          <h4>Enhanced</h4>
          <img src="${enhancedUrl}" style="max-width: 100%">
        </div>
      </div>
      <a href="${enhancedUrl}" download class="download-btn">Download Enhanced</a>
    </div>
  `
};

Use Case 2: Document Analysis (PDF)

Scenario: User uploads PDF, AI summarizes it

Form Fields:

  • File upload (PDF)
  • What to extract (select: Summary, Key Points, Action Items)
  • Email

n8n Workflow:

[Webhook]
   ↓
[Code: Decode PDF]
   ↓
[HTTP Request: OCR/Text extraction]
   ↓
[OpenAI: Analyze text]
   ↓
[Format results]
   ↓
[Email results + Webhook response]

PDF Processing:

// Save PDF temporarily
const fs = require('fs');
const pdfData = $json.body.form_data.field_document_file_data;
const buffer = Buffer.from(pdfData, 'base64');
fs.writeFileSync('/tmp/document.pdf', buffer);

// Extract text (using pdf-parse library)
const pdf = require('pdf-parse');
const dataBuffer = fs.readFileSync('/tmp/document.pdf');
const pdfText = await pdf(dataBuffer);

return {
  text: pdfText.text,
  pages: pdfText.numpages
};

Use Case 3: Image-to-Text (OCR)

Scenario: User uploads image with text, AI extracts it

Form Fields:

  • File upload (image)
  • Language (select: English, Spanish, French, etc.)

Using Google Vision:

const vision = require('@google-cloud/vision');
const client = new vision.ImageAnnotatorClient();

const imageBuffer = Buffer.from(
  $json.body.form_data.field_image_file_data,
  'base64'
);

const [result] = await client.textDetection({
  image: { content: imageBuffer }
});

const text = result.fullTextAnnotation.text;

return {
  output_html: `
    <div class="ocr-result">
      <h3>📝 Extracted Text</h3>
      <textarea rows="10" style="width:100%">${text}</textarea>
      <button onclick="navigator.clipboard.writeText('${text.replace(/'/g, "\\'")}')">
        Copy to Clipboard
      </button>
    </div>
  `
};

Use Case 4: Background Removal

Scenario: User uploads photo, AI removes background

Form Fields:

  • File upload (image)
  • Output format (PNG with transparency / White background)

Using remove.bg API:

const FormData = require('form-data');
const axios = require('axios');

const imageBuffer = Buffer.from(
  $json.body.form_data.field_photo_file_data,
  'base64'
);

const formData = new FormData();
formData.append('image_file_b64', $json.body.form_data.field_photo_file_data);
formData.append('size', 'auto');

const response = await axios.post('https://api.remove.bg/v1.0/removebg', formData, {
  headers: {
    'X-Api-Key': 'YOUR_API_KEY',
    ...formData.getHeaders()
  },
  responseType: 'arraybuffer'
});

const resultBase64 = Buffer.from(response.data).toString('base64');

return {
  output_html: `
    <div class="bg-removal-result">
      <h3>🎨 Background Removed!</h3>
      <img src="data:image/png;base64,${resultBase64}" style="max-width: 100%">
      <a href="data:image/png;base64,${resultBase64}" download="no-background.png">
        Download Image
      </a>
    </div>
  `
};

Use Case 5: Multiple File Processing

Scenario: User uploads multiple images for batch processing

Handling Multiple Files:

When multiple files are uploaded, they're sent as separate fields:

{
  "field_images_0_file_data": "base64...",
  "field_images_0_file_name": "photo1.jpg",
  "field_images_1_file_data": "base64...",
  "field_images_1_file_name": "photo2.jpg",
  "field_images_2_file_data": "base64...",
  "field_images_2_file_name": "photo3.jpg"
}

Process all files:

const formData = $json.body.form_data;
const files = [];

// Extract all uploaded files
Object.keys(formData).forEach(key => {
  if (key.includes('_file_data')) {
    const index = key.match(/_(\d+)_/)[1];
    const fileData = formData[`field_images_${index}_file_data`];
    const fileName = formData[`field_images_${index}_file_name`];

    files.push({
      data: fileData,
      name: fileName
    });
  }
});

// Process each file
const results = await Promise.all(
  files.map(file => processImage(file.data, file.name))
);

return { files: files.length, results };

Configuration & Limits

WordPress Limits

Default Settings:

  • Maximum file size: 25MB per file
  • Maximum total: 100MB per submission
  • Allowed types: See supported file types above

Server Requirements

PHP Settings (check php.ini):

upload_max_filesize = 25M
post_max_size = 100M
max_execution_time = 300
memory_limit = 256M

Check current limits:

<?php
echo 'upload_max_filesize: ' . ini_get('upload_max_filesize') . '<br>';
echo 'post_max_size: ' . ini_get('post_max_size') . '<br>';
echo 'max_execution_time: ' . ini_get('max_execution_time') . '<br>';
echo 'memory_limit: ' . ini_get('memory_limit');
?>

Performance Considerations

Large files impact:

  • ⏱️ Longer upload time
  • 💾 More memory usage
  • 🕐 Increased processing time
  • 🔄 Higher timeout risk

Optimize:

  1. Compress images before upload (client-side)
  2. Use async processing for large files
  3. Stream uploads instead of loading entirely
  4. Set realistic limits based on your use case

Troubleshooting

File Upload Not Working

Symptoms:

  • Upload button does nothing
  • Drag & drop doesn't work
  • No file preview

Solutions:

1. Check JavaScript Console:

F12 → Console tab → Look for errors

2. Verify file type:

// Accepted types must match
Accept: image/png,image/jpeg

3. Check file size:

File must be < 25MB
Total must be < 100MB

4. Browser compatibility:

  • Chrome: ✅ Full support
  • Firefox: ✅ Full support
  • Safari: ✅ Full support (iOS 11+)
  • Edge: ✅ Full support

File Too Large Error

Error Message:

"File 'photo.jpg' is too large. Maximum size is 25MB."

Solutions:

1. Compress the image:

  • Use TinyPNG.com
  • Use image editing software
  • Reduce dimensions

2. Increase PHP limits:

; In php.ini
upload_max_filesize = 50M
post_max_size = 100M

3. Use multiple smaller files:

  • Split large files
  • Upload in batches

File Not Received by Webhook

Check webhook payload:

1. In n8n execution:

Click failed execution → View input data

2. Look for file fields:

{
  "field_image_file_data": "Should be here",
  "field_image_file_name": "photo.jpg"
}

3. Common issues:

  • Field name mismatch
  • Form not submitting correctly
  • JavaScript error preventing submission

Base64 Decoding Errors

Error: Invalid base64 string

Solution:

// Ensure proper decoding
try {
  const buffer = Buffer.from(fileData, 'base64');
  return { success: true, buffer };
} catch (error) {
  return {
    error: true,
    message: 'Invalid file data: ' + error.message
  };
}

Preview Not Showing

For images:

// FileReader API creates preview
const reader = new FileReader();
reader.onload = (e) => {
  preview.src = e.target.result; // Should show image
};
reader.readAsDataURL(file);

If still not working:

  1. Check image format (must be valid)
  2. Check file corruption
  3. Try different browser
  4. Check console for errors

Best Practices

User Experience

✅ DO:

  • Show clear file requirements
  • Display upload progress
  • Provide instant validation feedback
  • Show file previews
  • Allow removing files before submit
  • Give clear error messages

❌ DON'T:

  • Hide file size limits
  • Allow unlimited uploads
  • Skip validation
  • Ignore user feedback

Security

✅ DO:

  • Validate file types server-side
  • Check file sizes
  • Scan for malware (if possible)
  • Sanitize filenames
  • Use secure temporary storage

❌ DON'T:

  • Trust client-side validation only
  • Execute uploaded files
  • Store files permanently without scanning
  • Allow dangerous file types (.exe, .php, etc.)

Performance

✅ Optimize:

  • Compress images before processing
  • Use CDN for storing results
  • Implement file size limits
  • Clean up temporary files
  • Use async processing for large files

File Storage

Options:

1. Temporary Processing:

  • Decode → Process → Delete
  • No permanent storage needed
  • Best for: AI processing, transformations

2. Cloud Storage:

  • Upload to S3, Google Cloud, etc.
  • Generate public URLs
  • Best for: Results, user galleries

3. WordPress Media Library:

  • Upload as attachment
  • Managed by WordPress
  • Best for: Permanent storage, galleries