Offline Conversion Import + Meta Ads Setup Guide

I audit offline conversion setups for Meta every month, and about 60% of them are broken. Usually it’s match rate issues (sub-30%) or delayed attribution because someone skipped the hashing step or used the wrong API endpoint. Meta’s offline conversion system is powerful when set up right, but the devil is in the data quality details.

What You’ll Have Working By The End

Prerequisites

Step 1: Configure Offline Event Set in Meta

First, you need to create an Offline Event Set in Meta Business Manager. This is where your offline conversions will be housed.

Navigate to Events Manager → Data Sources → Add New Data Source → Offline Conversions.

Critical configuration:

The Event Set ID looks like this: 1234567890123456. Copy it immediately because you’ll reference it in every API call.

Match Key Selection (this is where most setups break):

More match keys = higher match rates, but also higher privacy compliance burden.

Step 2: Set Up Data Processing and Hashing

Meta requires all PII to be SHA-256 hashed before transmission. I see unhashed data attempts in about 30% of broken setups.

Required hashing format:

Here’s the processing code I use for most client setups:

const crypto = require('crypto');

function hashForMeta(value, type) {
  if (!value) return null;
  
  let processed = value.toString().toLowerCase().trim();
  
  if (type === 'phone') {
    // Remove all non-numeric, add country code if missing
    processed = processed.replace(/[^\d]/g, '');
    if (processed.length === 10 && !processed.startsWith('1')) {
      processed = '1' + processed; // Add US country code
    }
  }
  
  if (type === 'email') {
    processed = processed.toLowerCase().trim();
  }
  
  return crypto.createHash('sha256').update(processed).digest('hex');
}

// Usage example
const hashedEmail = hashForMeta('John.Doe@Example.com', 'email');
// Output: 'b1c2d3e4f5...' (actual hash)

Common hashing mistakes I fix:

Step 3: Build the Upload Infrastructure

You have two approaches: API integration (recommended) or manual CSV uploads. API gives you automation and real-time match rate feedback.

API Integration Setup

Endpoint: https://graph.facebook.com/v19.0/{offline_event_set_id}/events

Required headers:

const headers = {
  'Content-Type': 'application/json',
  'Authorization': `Bearer ${ACCESS_TOKEN}`
};

Payload structure:

const payload = {
  data: [
    {
      event_name: 'Purchase', // or 'Lead', 'CompleteRegistration', etc.
      event_time: 1703894400, // Unix timestamp
      user_data: {
        em: ['hashed_email_1', 'hashed_email_2'], // Multiple emails if available
        ph: ['hashed_phone_1'],
        fn: ['hashed_first_name'],
        ln: ['hashed_last_name'],
        ct: ['hashed_city'],
        st: ['hashed_state'],
        zp: ['hashed_zip']
      },
      custom_data: {
        currency: 'USD',
        value: 99.99,
        order_id: 'ORD-12345'
      }
    }
  ],
  test_event_code: 'TEST12345' // Remove for production
};

Which approach should you use?

CSV Upload Alternative

If you’re not ready for API integration, CSV uploads work but require manual intervention.

CSV format requirements:

event_name,event_time,email,phone,first_name,last_name,value,currency
Purchase,1703894400,hashed_email,hashed_phone,hashed_fn,hashed_ln,99.99,USD

Upload via Events Manager → Offline Event Set → Upload Events → Choose File.

Step 4: Deploy and Automate

For production setups, I typically deploy the upload script on Google Cloud Run or AWS Lambda with scheduled triggers.

Cloud Run deployment example:

FROM node:18-slim
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 8080
CMD ["node", "index.js"]

Scheduled execution options:

Automation frequency I recommend:

More frequent uploads don’t improve attribution but can hit rate limits.

Step 5: Configure Attribution Settings

In Meta Ads Manager, navigate to Attribution Settings to optimize how offline conversions impact campaign optimization.

Critical settings:

Which attribution window should you use?

Testing & Verification

Step 1: Test Event Code During setup, use the test_event_code parameter. This lets you send test data without affecting campaign delivery.

In Events Manager → Test Events, you’ll see:

Step 2: Production Verification Remove the test event code and send real data. Check:

In Events Manager:

In Ads Manager: Navigate to Campaigns → Columns → Customize → Offline Conversions. You should see:

Cross-verification query:

-- Check your source data count vs Meta received count
SELECT 
  DATE(created_at) as date,
  COUNT(*) as total_conversions,
  SUM(value) as total_value
FROM offline_conversions 
WHERE created_at >= CURRENT_DATE - 7;

Red flags that indicate problems:

Troubleshooting

Problem: Match rates below 30% Check your hashing implementation. Most low match rates come from incorrect data preprocessing. Verify phone numbers include country codes and emails are properly lowercased before hashing.

Problem: Events uploading but not attributing to campaigns Your attribution window might be too narrow, or the event_time timestamps are outside the attribution window. Check that timestamps are recent (within 28 days) and in correct Unix format.

Problem: API calls returning 400 errors Usually malformed JSON or incorrect event names. Meta accepts specific event names: Purchase, Lead, CompleteRegistration, AddToCart, InitiateCheckout, AddPaymentInfo, Subscribe. Custom event names won’t work for optimization.

Problem: Duplicate events skewing data Implement deduplication using order_id or similar unique identifiers in custom_data. Meta will deduplicate based on this field plus user matching data.

Problem: Upload delays causing attribution gaps Set up monitoring for your upload jobs. I use a simple health check that alerts if uploads are more than 6 hours delayed. Attribution degrades significantly after 72 hours.

Problem: High API error rates during batch uploads You’re likely hitting rate limits. Meta allows 1000 events per API call and has hourly limits. Implement exponential backoff and split large batches into smaller chunks of 500-1000 events.

What To Do Next

Once your offline conversions are flowing, optimize your setup with Enhanced Conversions API for better match rates, or set up Server-Side Tracking for a complete first-party data infrastructure.

For lead generation specifically, check out our Lead Form to Offline Conversions guide for automated lead-to-close tracking.

Need help getting this setup right? Get a free tracking audit — I’ll review your current offline conversion configuration and identify what’s breaking your match rates.

This guide is part of the Offline Conversion Tracking Hub — complete guides for tracking offline conversions across all major ad platforms.