How to repeat action(s) in your Zap for a variable number of values

How to repeat action(s) in your Zap for a variable number of values
Userlevel 7
Badge +3
  • Zapier Staff
  • 21 replies

Last Updated: 05-27-2021

Update

There is now a 3rd option for accomplishing this: Looping by Zapier!

Looping by Zapier was built with some of the issues in mind that could crop up using a Code Step, like not inputting Line Item data with null values properly. It works similarly to the Code Step below behind the scenes, but has some nice bells and whistles, like Line Item support and more.

You can read about it here: https://zapier.com/help/create/other-functions/loop-your-zap-actions

You can add it to your Zaps by searching for Looping by Zapier as the app when adding a new Step.

Intro

Sometimes we want to run an Action or set of Actions more than once in our Zaps. Today I’d like to show you how we can do that if the number of times we want to run that action is variable. 

In the world of programming, we can create loops that run a bit of code once for each of a set of values. We can do this in a Zap as well. If you don’t know how to code, that’s ok! It’s my hope that with this guide, you won’t need to know how to take advantage of this.

Let’s say I have a Trigger that provides a Line Item (array) or comma separated text containing email addresses and first names and I’d like to send a customized email to each one of them:

If we tried to map the email addresses into the “To:” field, that line item would be converted into comma separated text, so a single email would be sent to all the recipients, but they would all see each other’s email address. Worse, the names would be a comma separated text list in the greeting of our email.

What we really want is for the Zap to run the email Step once for each email and name so that each recipient gets a separate email. 

The ideas that we’ll explore would also apply to circumstances where we want to add multiple contacts or leads to a CRM, create multiple documents, send multiple text messages, and more. If an Action supports line items, that support can be used many times for a similar effect, like adding multiple rows to a spreadsheet in Google Sheet’s “Create Spreadsheet Row(s)”. Many actions don’t support line items, and that’s where these techniques come in handy. 

There are two ways to create a loop to repeat one or more actions for different values:

Option 1: Use Google Sheets as an intermediary

This method involves setting up two Zaps and a Google Sheet:

Google Sheet

  • Create a header for each value that you want to repeat in one or more actions

Zap 1

  • Your original Trigger
  • Actions before you want to loop
  • If the values aren’t already in Line Item format, use the Formatter App’s Utility Action: Line Itemizer transform to convert the values into line items (unless they already are)
  • Action: Google Sheets: Create Spreadsheet Row(s) (Mapping each value you want to send to  into the various fields in the sheet - 1 or more rows will be created for the line items. You can mix and match single values and line item values. Line item values each be used once per row. Single values will be repeated for each row - think values like name or email address)

Zap 2 (runs once for each row created by the line items in Zap 1): 

  • Trigger: Google Sheets: New Spreadsheet Row
  • Action: One or more Action(s) that you want to repeat 

In summary, Zap 1 “sets up” the loop, and Zap 2 runs the looped actions with the values posted to each row of the sheet.

Option 2: Use a “Code by Zapier” Action (sometimes referred to as a “Code Step”) to “fork” a Zap

Option 1 works well enough, but it is more difficult to manage over time than a single Zap because we have two Zaps and a spreadsheet to keep track of. Let’s take a look at how using a small amount of reusable code, we can keep things in a single Zap.

Most Steps in Zapier give an output of one JSON object wrapped in an array. When using any value from that object in a subsequent Step, that Step will run once. If we use a Code Step to output multiple JSON objects of the same structure wrapped in an array, the later Steps will run once for each object in the array instead, creating the loop we’re looking for. 

A common example of this is that you're already familiar with is a Zap Trigger. Triggers that ask an app for new data to Trigger on get 0 or more objects in an array returned, and then the Zap runs once for each object. 

​When we’re testing this in the Zap editor, similar to how we can only use one Sample from a Trigger at a time, we’ll only see the first object, and the Zap Steps will only run once when testing. When running live, they will run once per object (set of values).

First, let’s take a look at the values we’re going to input into the Code Step. They could be Line Items like this:

Or comma separated text like this:

When we map the values into the Code Step, they will be converted to comma separated text if they’re not already, so the both examples above will work the same way.

When you’re adding the Code Step to your Zap, you’ll specifically want to use “Run Javascript” if you’re using the code I’ve included here.

When we map those values into the Code Step, we’ll want to types names for each set of values on the left of the Input Data fields (green highlight) and map the actual series of values on the right (purple):

You can paste the following Code into the Code Field as-is. You won’t need to modify it all, regardless of the names and quantities of different values you’re using. It will detect the names of your values automatically from the Input Data field (green highlight). Here’s the code to copy and paste:

/* Add as many Input Data fields as you like above as comma seperated text or mapped line items (will be 
converted to comma seperated text). This code will find each Input Data field and output an array of
objects with the same structure that can be used to "Fork" the Zap.
Example: https://cdn.zappy.app/9de81901f3750ef26bcbbd0737b0937b.png */

// get Input Data field names
let keys = Object.keys(inputData)
let data = [];

// loop through each Input Data field
for (let key of keys) {
// split the contents of each Input Data field on the commas into an array
let li = inputData[key].split(",");
for (let i=0; i<li.length; i++) {
if (typeof data[i] === "undefined") data[i] = {};
data[i][key] = li[i];
// add a record number (in case we want to break the fork/loop with a Filter)
data[i].recordNumber = i+1;
}
}

// preview the whole data structure in the output
console.log(data);
// output the data
output = data;

When you test the Code Step, you’ll see something like this:

As you can see, the the values that we get back (in red) match the names of the Input Data fields and additionally have a “recordNumber” value, but we only get the first set of values to test with, just like when we’re testing a Trigger. By mapping any of those values into a field in the next Action, when the Zap runs live, that Action will be repeated for each set of values. 

In order to give you a better preview of what will actually happen with the live Zap, I’ve set the code to output a “log” that shows all the sets of value (highlighted in green). You can see how the first record is listed there, too (in red).

Here’s what it looks like if we map those values into an Email by Zapier action:


​Once the Zap starts looping, every Action from that point on will loop and run multiple times. If we need to break the loop, we can do that by:

  • Where we want the loop to stop, add a Filter that only continues the Zap if the “Record Number” value exactly matches to “1”. 
  • The Filter will loop, too, but will only pass once for the first set of values in the loop, meaning that we’ll be back to not looping for the Actions after that. 

If we don’t need to run any Actions just once after the ones that we want to loop, we don’t need to worry about breaking the loop.


And that should do it! With these workflows, Zap Actions that can only send a single set of values to an app can send multiple sets of values instead!

If you have any questions about this, I’d be happy to field them here!

Please note

We aren't always able to help with Code questions via Zapier Support because not everyone on the Support Team is familiar with Javascript and Python, and supporting custom code is technically outside of our scope of support. A great place to ask if we can't support you directly is here in our community or on Stack Overflow by tagging your question "Zapier": https://stackoverflow.com/questions/tagged/zapier

 


This post has been closed for comments. Please create a new post if you need help or have a question about this topic.

39 replies

Userlevel 7
Badge +3

Hi @jonah and @ForYourIT,

Thanks for the questions and answers here! @ForYourIT is correct that we need to keep those limitations in mind, though in this case the answer is likely something else. 

I consulted with our Support Escalations team and I learned that the maximum number of times we can loop/fork in a Zap is 250. With 732 values to loop through, we exceed that limit and the Zap won’t work. 

I don’t believe that number can be changed, but I’m looking into learning more about this, and if there is a good workaround/solution, I’ll post another reply.

Userlevel 2

OMG OMG! I was banging my head over the last few days to achieve this functionality. You made my day @TimS  😘🤯😍🔥

Userlevel 1

@TimS You are an absolute godsend.

 

Not only have you been able to the solution to solve a very specific problem but you have provided it in a way that can be reused to solve any number of other problems using only the Zapier inputs!

 

Seriously man, great work, the world needs more people capable of providing solutions like this one, if you are ever in New Zealand I owe you a drink of your choosing.

Userlevel 1

@TimS - Worked like a charm!  Thanks very much.

Userlevel 1

Just wanted to chime in and say this saved my day (and a ton of my time in the future)!  Thanks for sharing!

Userlevel 7
Badge +3

Hi Andreas, nice work getting this all set up!

You’re right that the code works best when there are no commas in your values, but in your case, there is a way you can work around this by using a Formatter Step for each Input Data Value before the loop starts.

Currently, you have Line Items mapped into your Input Data fields, and what happens is the Code Step converts those into comma delimited text and then sends them into the Code. If we use a Formatter Utilities Action with the “Line Item to text” transform, then we can choose our own delimiter. 

Instead of outputting the text with commas in-between, I like to use three pipes: |||

Then, in the Code Step if you change the Input Data values to your 3-pipe delimited text from the Formatters, you can change the code you highlighted to split on the pipes instead of single commas and that will protect your actual value containing a comma.

That line would change to: let li = inputData[key].split(“|||”);

And that should do the trick!

Userlevel 1

Wow, this will work for sure! I will do it and report back on results, thanks so much...

Userlevel 1

Hey Tim, 

Thanks for this solution! I tried the code out and wanted to ask if there’s a way for the first line “Deal” to repeat? So that “Order 1” would be repeated for each “Product”? 

Right now, the zap doesn’t repeat the first line “deal”: 

 

Ideally, it would look like this: 

 

Any help is greatly appreciated! Thank you!

Userlevel 3
Badge +1

Here’s a little hack that serves me well in these situations:

When the various array items that generate the fork or loop have associated values - in one of my cases each is associated with a line item which has an image and a list of options.

Before hitting the fork I create a set of arrays (I could do this with an array of objects, too, but arrays are easier).

Before hitting the fork in the road I zero out a value in Storage.

As each loop is executed, I first retrieve the value and use it as an index to the earlier arrays.

Before ending the loop, I increment the value.

This is a tedious way of saying I use a storage variable as the index of a loop.

Userlevel 1

@TimS - Can you please help me out with using this code?  I’m trying to understand how to deal with blank values coming in to this step from a CSV.

 

Background:  I’m running a daily download from a wordpress website.  I then need to parse the data and pass it to a ticket in Hubspot.

 

It appears that the data is being read correctly from the CSV. 

 

The input data where I am getting blanks is the field RFP Toolkit. You can see that there are blanks in the CSV file.

 

I have not altered your original code.

 

The output log shows the 1 value being assigned to record 1, not to record 3.  And records 2, 3, 4 are blank.

 

I have also looked at your post about assigning default values to Code steps, but that resulted in the same output, with the 1 being assigned to the first record.

 

Any insight you could offer would be incredibly helpful.

 

Scott

Userlevel 7
Badge +3

@TimS is it possible to nest multiple loops? i.e. code step>using line items in step>another code step>using those line items?

Hey @David@Zapwise ! 
It is technically possible but not advisable. We discovered while working on the Looping by Zapier app that nested looped actions often get stuck in a playing state, so we prevent Zaps from turning on with multiple Looping Steps. That being said, we’re working on improving the way the underlying tech works for Looping so that in the future nested Looping will work.

Userlevel 7
Badge +3

I’m trying to understand how to deal with blank values coming in to this step from a CSV.


Hey @scottfmosley !

The reason that you’re getting those inconsistent results with the blank fields is that the Code by Zapier Step doesn’t have native line item fields. That means that each element of the line items from the CSV are converted into comma separated strings, and null (empty) values are dropped.

When we try to line up the different elements where some have had entries dropped, they get misaligned like that.

This is part of the reason that we created the Looping by Zapier Beta app. It has a “Create Loop from Line Items” Action that does essentially the same thing as the code here, but with proper Line Item fields so that data isn’t misaligned when there are null values, and we made the interface a bit nicer, too!

I’d definitely recommend trying the Looping by Zapier Action instead of the Code Step first.

If you find you wanted to do something custom in the code, you can read more about how to get line items into Code Steps intact in a more recent post I wrote here: 

It’s a long post, but it’s mostly screenshots because this is a tricky thing to get right!

Hi @jonah and @ForYourIT,

Thanks for the questions and answers here! @ForYourIT is correct that we need to keep those limitations in mind, though in this case the answer is likely something else. 

I consulted with our Support Escalations team and I learned that the maximum number of times we can loop/fork in a Zap is 250. With 732 values to loop through, we exceed that limit and the Zap won’t work. 

I don’t believe that number can be changed, but I’m looking into learning more about this, and if there is a good workaround/solution, I’ll post another reply.

Hello! Is there any update on this particular limitation? We’re running into the same problem.

My action is a webhook GET that returns an array of data that I cannot filter from this particular service (Paychex) due to an API limitation, so it is returning over 250 results in the JSON. It does, however, allow for pagination, but I’m not sure how to tackle that using Zapier.

Any ideas of a workaround to get the Javascript code to either work for >250 items OR alternatively, limit the number of responses using API pagination?

Any help is greatly appreciated!

Userlevel 3
Badge +1

Tim, if the array that kicks off the loop were parsed in such a way that groups of array items would Branch off to other zaps would the same limitation still apply? for example, could the first 100 values of the array the bundled up and sent to one's app while another hundred gets sent in a separate batch? Exactly how does the limitation apply?

Userlevel 1

Hi Tim, 

Amazing work, thanks so much! This opens up lot’s of possibilities.

I am trying my luck with the first option before cutting my teeth with the second.

It all seems to work perfectly, except that my line items contain some null values.

 

 

This results in uneven pasting onto the Google Sheet.

 

The Date and Status fields are not aligned with the message field…

What would you do in that case?🙏

Thanks!

Andreas

Userlevel 7
Badge +3

Hi Andreas!

You’re welcome, and I’m glad to see you giving this a try :)

I took a look at your screenshots, and I can’t quite tell why things are not lining up. If we’ve created the line items with Line Itemizer, even if you have null values, the resulting rows in the Google sheet should line up, with some blank cells where the null values were. At least the subject and status rows should be lining up because there don’t appear to be any nulls there.

I see one “Subject” value in your line items “RE: Re: Note from...” that I don’t see in the spreadsheet screenshot, so I’m not sure what is happening there.

One suggestion I have here is if your date needs to be repeated for all the rows, for example, is to map in the single Date value in the Create Multiple Row(s) Step instead of the Line Item version. When you combine single values and line item values, the single values will be repeated once for each line.

For the other parts, it may be easier to troubleshoot if we could see the Zap setups. Because you’re not working on any Code Steps here, I’d recommend writing in to Support (https://zapier.com/app/get-help) if you still have questions about this one. If you could post the general answer here afterwards, that would be fantastic!

Best, Tim

Userlevel 1

Hi Tim, it now works perfectly for me! And I am able to format and filter the forked results, so that my spreadsheet looks perfect.

 

I do have one question though, which may not have a satisfactory answer 🤞 

For one of my values, there is a comma within the text. This means that the code steps splits the text in half when it tries to split it at the end of the value.

Is there any way to avoid this from happening or does the code work best when there are no commas within the value itself?

 

Userlevel 1

Hi Tim,

 

Is there a limit to the number of records / repeatable flows that can be played through the code?

 

This worked great when I tried it with zaps using a small number of records. Then I tried to set one up with a higher number of records (732 comma-separated values) and the zap seemed to get stuck and not play past the code.

 

Any thoughts?

 

Jonah

Userlevel 7
Badge +7

Hi @jonah I think I can answer your question.

The code by Zapier action has got some limitations. This is probably required so the system doesn’t get overused calculated by the usage, costs and amount of users. These are the following limitations:

  • The environment in which your Code steps run (AWS Lambda) has an I/O limit of 6MB. The total size of the code and the data processed by the Code cannot exceed that. If you're hitting this error, try to limit the amount of data your return from your function. For instance, don't return an entire JSON structure, just the keys you need.
  • Free users are limited to 1 second and 128mb of RAM. Paid users get well over double that at 10 seconds and 256mb of RAM. Your Zap will hit an error if you exceed these limits.

If you like, you can read more about this here. A solution within this limitations is already there however! If I you were one of my clients I would advice you to use AWS lambda yourself to run your code. I use it for some of my clients as well, and the great thing is you can activate it threw Zapier as well.

It does require some setting up of the environment, but it will allow you to run a bigger amount of data. Hope this helps you!

 

~ Bjorn

 

Userlevel 1
Badge

@TimS is it possible to nest multiple loops? i.e. code step>using line items in step>another code step>using those line items?

Hi - everyone on this thread is amazing and everything you’ve shown is SO CLOSE to helping me solve my problem. But not quite yet.

 

This is start-to-finish the outline of my Zap so far. I have users submit forms with multiple image attachments. I need each of those images to create its own line in an AirTable database.

 

 

 

Here is the end result. The top line is what is happening; the next 4 are what I want to happen (I am fixing these manually right now.)

 



Here’s my JavaScript section:

 

This is the output I get

 

 

 

And this is what I’m doing in the AirTable section (‘Preview’ is the name of the field in AirTable where the photo attachments are stored/viewed.)

 

 

Userlevel 1
Badge

This functionality is exactly what I needed. Typed in csv data fields and it created multiple records in Airtable.

I have input from Jotform that looks like this.

Configurable list

[{"Product":"8 \"","Quantity":"2","Flavour":"B Choc"},{"Product":"10\"","Quantity":"1","Flavour":"Lemon"},{"Product":"10\"","Quantity":"1","Flavour":"Vanilla"},{"Product":"12\"","Quantity":"2","Flavour":"Carrot"}]

Is there a way that your code could be adjusted to use this format or would it have to be extracted somehow and put into one of your 2 formats. Maybe some kind of Run Python in Code by Zapier. 

Python looks a bit complex to learn. 

Hi @TimS ,

Your code works wonderful to run a loop. I want to create a loop inside loop. as you can see in SS. I want to run first loop against the total line items and the second loop against the quantity.

Can you please help. 

 

Thanks and Stay Safe,

 

Shahzad

Userlevel 1
Badge

Your code worked perfectly. I added a code step to split my arrays. I use this to add multiple occurrences of the same record in Airtable.

 

 

My understanding of your fork step is that all of the steps after the fork will run as many times as the fork triggers. I would like to add a second independant fork step that would run after this fork completes to add another set of different records based on another set of data. Is this possible?

Userlevel 3
Badge +1

Chrisboat - While I’ve not tried it myself, it seems to me that you could add a filter step at the bottom of the first “fork” which would only continue if the index+1 = the size of the first set of values. The following step could retrieve the next array and process just as the last fork had done.

Again, I haven’t tried it, but it seems like a logical extension of the indexed array approach.