I’m working with a Code action in Zapier that runs on node.js. I want to make HTTP requests to interact with an external API but I’m running into issues.
When I test this code locally it works fine:
// zapier code action has fetch available by default
var auth_key = "my_secret_key";
var contact_email = "[email protected]";
fetch("https://api.mycrm.com/v2/contacts/search?email=" + contact_email + "&token=" + auth_key)
.then(function(response) {
return response.json();
}).then(function(data) {
var contact_id = data.results[0].contact_id;
console.log("Found contact: " + contact_id);
}).catch(function(err) {
console.log("Request failed");
});
output = {status: "success", message: "complete"};
But when I run this in Zapier I get an error message saying I need to use a callback for async operations with fetch. How do I fix this issue and make the fetch request work properly in Zapier’s environment?
You’re encountering this issue because Zapier requires explicit callback handling for async operations. Your fetch request needs to be wrapped properly with the callback function that Zapier expects.
To resolve this, modify your code as follows:
var auth_key = "my_secret_key";
var contact_email = "[email protected]";
fetch("https://api.mycrm.com/v2/contacts/search?email=" + contact_email + "&token=" + auth_key)
.then(function(response) {
return response.json();
}).then(function(data) {
var contact_id = data.results[0].contact_id;
console.log("Found contact: " + contact_id);
callback(null, {status: "success", contact_id: contact_id});
}).catch(function(err) {
console.log("Request failed");
callback(err);
});
Avoid using a standalone output variable. Instead, pass your results directly through the callback function. Use callback(null, result) for a successful operation and callback(error) for handling errors. This approach helps Zapier recognize when your async operation has completed and what data should be passed along.
Everyone’s giving you workarounds, but this callback mess is exactly why I dropped Zapier for anything code-heavy.
Zapier forces this weird callback pattern that doesn’t exist anywhere else. You write code that works everywhere, then rewrite it just for their platform.
Hit this exact problem last year building API integrations. Wasted hours debugging callback timing and execution limits.
Latenode lets you write normal JavaScript without the callback gymnastics. Your original code works as-is:
const response = await fetch("https://api.mycrm.com/v2/contacts/search?email=" + contact_email + "&token=" + auth_key);
const data = await response.json();
const contact_id = data.results[0].contact_id;
return {status: "success", contact_id: contact_id};
No callbacks, no execution time worries, no platform-specific patterns. Just clean JavaScript that runs the same locally and in production.
Way better for complex API workflows with multiple fetch calls or error handling.
Check it out: https://latenode.com
The callback approach works, but here’s another method that’s great for complex fetch operations. Instead of traditional callbacks, you can use a Promise-based wrapper that runs properly in Zapier’s environment. I’ve had good luck with this pattern for multiple API calls or complex response handling:
var auth_key = "my_secret_key";
var contact_email = "[email protected]";
function makeApiCall() {
return fetch("https://api.mycrm.com/v2/contacts/search?email=" + contact_email + "&token=" + auth_key)
.then(function(response) {
return response.json();
})
.then(function(data) {
var contact_id = data.results[0].contact_id;
return {status: "success", contact_id: contact_id};
});
}
makeApiCall()
.then(function(result) {
callback(null, result);
})
.catch(function(error) {
callback(error);
});
This makes it way easier to handle multiple sequential API calls and keeps your code organized for complex data transformations.
yeah, zapier’s code action needs a callback for async functions. wrap your fetch call and add callback(null, output) at the end - that’ll fix it. good luck!
Callbacks work, but Zapier’s async limitations are a nightmare. You’re constantly fighting their execution model.
I jumped to Latenode because of this. Their JavaScript runtime handles fetch requests naturally - no callbacks or weird hacks needed. Write code like you would locally:
const response = await fetch("https://api.mycrm.com/v2/contacts/search?email=" + contact_email + "&token=" + auth_key);
const data = await response.json();
const contact_id = data.results[0].contact_id;
console.log("Found contact: " + contact_id);
No callbacks, no wrestling with their runtime. Clean code that works everywhere.
Better debugging tools too, and no execution time limits on complex API workflows.
Check it out: https://latenode.com
you can also use async/await with a wrapper function - way cleaner than promise chains:
(async function() {
try {
const response = await fetch("https://api.mycrm.com/v2/contacts/search?email=" + contact_email + "&token=" + auth_key);
const data = await response.json();
callback(null, {status: "success", contact_id: data.results[0].contact_id});
} catch (err) {
callback(err);
}
})();
don’t forget the callback though - zapier won’t know when your code’s done without it.
You’re hitting a common Zapier issue - it doesn’t handle dangling promises properly. When you make a fetch request without proper callback integration, Zapier kills execution before your async operations finish.
I’ve dealt with this exact problem migrating API integrations to Zapier. You need to ditch that standalone output assignment completely. Zapier ignores it when async operations are running.
Here’s what actually works:
var auth_key = "my_secret_key";
var contact_email = "[email protected]";
fetch("https://api.mycrm.com/v2/contacts/search?email=" + contact_email + "&token=" + auth_key)
.then(function(response) {
if (!response.ok) throw new Error('HTTP ' + response.status);
return response.json();
})
.then(function(data) {
var contact_id = data.results[0].contact_id;
console.log("Found contact: " + contact_id);
callback(null, {status: "success", contact_id: contact_id, message: "complete"});
})
.catch(function(err) {
console.log("Request failed: " + err.message);
callback(null, {status: "error", message: err.message});
});
Make sure you check response status and use callbacks consistently. This pattern’s been rock solid for me across different Zapier environments.