How to search for existing record using email field in Airtable database

I need help with checking if a customer already exists in my Airtable database before creating a new entry. I want to search by email address first and only add the customer if they don’t exist yet.

const AirtableLib = require('airtable');
const database = new AirtableLib({ apiKey: process.env.API_TOKEN }).base(process.env.BASE_ID);

app.post('/createCustomer', (req, res) => {
  const { userId, fullName, emailAddress, avatarUrl, authProvider } = req.body;
  database('customers').find({filterByFormula: `FIND(emailAddress = '${emailAddress}')`}, function(error, result) {
    if (error) res.status(400).send(error);
    console.log('Found record:', result.id);
    database('customers').replace([{"fields": { userId, fullName, emailAddress, avatarUrl, authProvider}}], function(error, results) {
      if (error) console.log(error);
      else console.log(results[0]) 
      res.status(200).send(results[0]._rawJson);
    });
  });
});

I keep getting this error message:

AirtableError {
  error: 'NOT_FOUND',
  message: 'Could not find what you are looking for',
  statusCode: 404
}

I also attempted using select method instead:

database('customers').select({filterByFormula: `FIND(emailAddress = '${emailAddress}')`}, function(error, result) {...

But that gives me a different error saying select only accepts one parameter and I should use eachPage or firstPage instead. What’s the correct way to do this?

Had this exact same issue last month. You’re mixing up Airtable’s methods - find() needs a specific record ID, but select() is what you want for filtering. And replace() won’t work without an existing record ID.

Here’s what fixed it for me: use select() with eachPage() instead of firstPage(). I’ve found firstPage() can be flaky with certain filters:

database('customers').select({
  filterByFormula: `{emailAddress} = '${emailAddress}'`
}).eachPage((records, fetchNextPage) => {
  if (records.length > 0) {
    // Customer exists
    console.log('Existing customer:', records[0].id);
    res.status(200).send(records[0]._rawJson);
  } else {
    // Create new customer
    database('customers').create({
      userId, fullName, emailAddress, avatarUrl, authProvider
    }, (err, record) => {
      if (err) return res.status(400).send(err);
      res.status(201).send(record._rawJson);
    });
  }
}, (err) => {
  if (err) res.status(400).send(err);
});

Double-check your field name is exactly emailAddress in Airtable - spacing matters.

Two problems with your code. First, your FIND formula is wrong - you’re treating it like an equality check when FIND searches for text positions in strings. Second, you’re calling replace() without a record ID.

Hit this same issue months ago. Here’s what works:

app.post('/createCustomer', async (req, res) => {
  const { userId, fullName, emailAddress, avatarUrl, authProvider } = req.body;
  
  try {
    const records = await database('customers').select({
      filterByFormula: `{emailAddress} = ">${emailAddress}"`
    }).all();
    
    if (records.length > 0) {
      // Customer exists
      res.status(200).send(records[0]._rawJson);
    } else {
      // Create new customer
      const newRecord = await database('customers').create({
        userId, fullName, emailAddress, avatarUrl, authProvider
      });
      res.status(201).send(newRecord._rawJson);
    }
  } catch (error) {
    res.status(400).send(error);
  }
});

Async/await beats callback hell every time. Switched to double quotes in the formula too - single quotes break with email addresses that have apostrophes.

Double-check your Airtable field is named “emailAddress” and not “Email” or something else. That 404 usually means field names don’t match.

Hit this same issue a few weeks ago. You’re using find() which needs a record ID, not a search query. That FIND formula syntax is for searching text strings, not exact matches.

Something others missed - you’re calling replace() but that needs the record ID as the first parameter, which you don’t have. Use create() for new records instead.

Watch your field names too. Mine worked fine in testing but crashed in production because my Airtable field was “Email Address” with a space, not “emailAddress”. The error won’t tell you this.

Log your exact field names from the Airtable schema first, then try the select approach others mentioned. The all() method from the latest answer is probably cleanest since it handles pagination without callback headaches.

your FIND syntax is completely wrong. FIND searches for text inside strings - it doesn’t compare values. just use {emailAddress} = '${emailAddress}' and drop the FIND wrapper. also double-check that your field name matches exactly what’s in Airtable - it’s case sensitive!

Your filterByFormula syntax is wrong, and you can’t use find() like that. Airtable’s find method needs a record ID, not a filter formula. Use select with firstPage to search by email instead.

Here’s the fix:

app.post('/createCustomer', (req, res) => {
  const { userId, fullName, emailAddress, avatarUrl, authProvider } = req.body;
  
  database('customers').select({
    filterByFormula: `{Email} = '${emailAddress}'`
  }).firstPage((error, records) => {
    if (error) {
      return res.status(400).send(error);
    }
    
    if (records.length > 0) {
      // Customer exists, update or return existing
      console.log('Customer already exists:', records[0].id);
      res.status(200).send(records[0]._rawJson);
    } else {
      // Create new customer
      database('customers').create([{
        fields: { userId, fullName, emailAddress, avatarUrl, authProvider }
      }], (error, results) => {
        if (error) return res.status(400).send(error);
        res.status(201).send(results[0]._rawJson);
      });
    }
  });
});

Double-check that your email field name in Airtable matches what you’re using in the formula. The {Email} syntax with curly braces works better than bare field names.