Await Crypto node

Hi! First time posting to this forum.

I’ve built a workflow to get orders from an Airtable database and send the details to Meta’s Conversions API. I had to add a bunch of nested Merge nodes to get it to await the results of the hashing from the Crypto node. Without this, it proceeds once the first node has executed.

This makes it extremely messy, and even more complicated if I want to add additional encrypted nodes, because Merge can only accept two inputs.

Is there a way to await the completion of every node up until a certain point, or a better way to do this?

Hi @nickboyce, welcome to the community!

Without knowing your data structure it’s a bit hard to think about alternatives here. Perhaps you can share your actual workflow rather than a screenshot to get an idea of what each of your nodes is doing? You can do this by simply selecting everything on your canvas, then pressing Ctrl+C to copy it, and finally using Ctrl+V to paste it here on the forum.

It’d be great if you can also share an example of the JSON data your Airtable node passes on. You can of course redact anything confidential, it’d just be good to understand your data structure.

Thank you :slight_smile:

2 Likes

Attached is a sample of the data (I’ve redacted some of the values)

Basically every value that contains personally identifiable information to the Meta Conversions API needs to be hashed. And because I can’t use the hashing functions inside the code node, I need to create individual variables. I’m sure there’s a better way.

Here is the workflow:

{
  "meta": {
    "instanceId": "c6c7c048129762f0bf46b86f8707ff88a251d7ec7d08eadf32c7fd95399cfe72"
  },
  "nodes": [
    {
      "parameters": {},
      "id": "86b127b5-f785-47b7-84cc-4783eb38890c",
      "name": "When clicking \"Execute Workflow\"",
      "type": "n8n-nodes-base.manualTrigger",
      "typeVersion": 1,
      "position": [
        1620,
        360
      ]
    },
    {
      "parameters": {
        "operation": "list",
        "application": {
          "__rl": true,
          "value": "apphcg0ehA4NOvoA0",
          "mode": "id"
        },
        "table": {
          "__rl": true,
          "value": "tblHy4HsxFY5ntVwz",
          "mode": "id"
        },
        "returnAll": false,
        "limit": 5,
        "additionalOptions": {
          "filterByFormula": "AND(SEARCH(\"blike.com\", {Personal Email}) = 0, {Payment Status} = 'success')",
          "sort": {
            "property": [
              {
                "field": "Time",
                "direction": "desc"
              }
            ]
          }
        }
      },
      "id": "f553fdea-4fd5-4a45-83e2-a9dbd2f3445e",
      "name": "Get records from Airtable",
      "type": "n8n-nodes-base.airtable",
      "typeVersion": 1,
      "position": [
        1840,
        360
      ],
      "credentials": {
        "airtableApi": {
          "id": "3",
          "name": "Airtable account"
        }
      }
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://graph.facebook.com/v17.0/1037929247047073/events",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "facebookGraphApi",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ $json }}",
        "options": {}
      },
      "id": "aef718c2-3298-40c9-88ee-391f88644293",
      "name": "Send CAPI payload",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.1,
      "position": [
        3480,
        360
      ],
      "credentials": {
        "httpHeaderAuth": {
          "id": "JRXNx2BO3EHmCV36",
          "name": "Header Auth account"
        },
        "facebookGraphApi": {
          "id": "1",
          "name": "Facebook Graph account"
        }
      }
    },
    {
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "return { \n\t\"data\":[\n      {\n        \"action_source\":\"website\",\n        \"event_name\":\"Purchase\",\n        \"event_time\": Math.floor(new Date($('Merge3').item.json.createdTime).getTime() / 1000),      \n        \"user_data\":{\n          \"em\": $('Merge3').item.json.em_hash,\n          \"fn\": $('Merge3').item.json.fn_hash,\n          \"ln\": $('Merge3').item.json.ln_hash,\n          \"ct\": $('Merge3').item.json.ct_hash,\n          \"subscription_id\": $('Merge3').item.json.fields['Quote Number']\n        },\n        \"custom_data\": {\n            \"currency\": \"GBP\",\n            \"value\": $('Merge3').item.json.fields['Monthly Cost']\n         },\n      }\n\t],\n  \t\"test_event_code\": \"TEST11286\"\n}"
      },
      "id": "651d6873-2dcd-405b-ade3-49a27a1b59b2",
      "name": "Code",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        3200,
        360
      ]
    },
    {
      "parameters": {
        "type": "SHA256",
        "value": "={{ $json.fields['Personal Email'] }}",
        "dataPropertyName": "em_hash"
      },
      "id": "559947fb-ed0a-4d63-be6b-5fa29e945dde",
      "name": "em",
      "type": "n8n-nodes-base.crypto",
      "typeVersion": 1,
      "position": [
        2320,
        640
      ]
    },
    {
      "parameters": {
        "type": "SHA256",
        "value": "={{ $json.fields['First Name'] }}",
        "dataPropertyName": "fn_hash"
      },
      "id": "bacaca56-f5e5-4ee2-b121-60b8bbfedeff",
      "name": "fn",
      "type": "n8n-nodes-base.crypto",
      "typeVersion": 1,
      "position": [
        2320,
        100
      ]
    },
    {
      "parameters": {
        "type": "SHA256",
        "value": "={{ $json.fields['Surname'] }}",
        "dataPropertyName": "ln_hash"
      },
      "id": "7a6db349-497b-4bba-b706-93bff682bb20",
      "name": "ln",
      "type": "n8n-nodes-base.crypto",
      "typeVersion": 1,
      "position": [
        2320,
        280
      ]
    },
    {
      "parameters": {
        "type": "SHA256",
        "value": "={{ $json.fields['Town'] }}",
        "dataPropertyName": "ct_hash"
      },
      "id": "3cca0f93-fcc1-4447-b734-d4d8d857b874",
      "name": "ct",
      "type": "n8n-nodes-base.crypto",
      "typeVersion": 1,
      "position": [
        2320,
        460
      ]
    },
    {
      "parameters": {
        "mode": "combine",
        "mergeByFields": {
          "values": [
            {
              "field1": "fields['Quote Number']",
              "field2": "fields['Quote Number']"
            }
          ]
        },
        "options": {}
      },
      "id": "57fca73c-510a-490c-bdbf-8d6e1897a0e8",
      "name": "Merge1",
      "type": "n8n-nodes-base.merge",
      "typeVersion": 2.1,
      "position": [
        2660,
        260
      ]
    },
    {
      "parameters": {
        "mode": "combine",
        "mergeByFields": {
          "values": [
            {
              "field1": "fields['Quote Number']",
              "field2": "fields['Quote Number']"
            }
          ]
        },
        "options": {}
      },
      "id": "edbf6613-ef2a-476b-b542-d698c2cf70d7",
      "name": "Merge2",
      "type": "n8n-nodes-base.merge",
      "typeVersion": 2.1,
      "position": [
        2660,
        460
      ]
    },
    {
      "parameters": {
        "mode": "combine",
        "mergeByFields": {
          "values": [
            {
              "field1": "fields['Quote Number']",
              "field2": "fields['Quote Number']"
            }
          ]
        },
        "options": {}
      },
      "id": "faa68e29-67e5-484c-b600-eb1ea92859af",
      "name": "Merge3",
      "type": "n8n-nodes-base.merge",
      "typeVersion": 2.1,
      "position": [
        2920,
        360
      ]
    }
  ],
  "connections": {
    "When clicking \"Execute Workflow\"": {
      "main": [
        [
          {
            "node": "Get records from Airtable",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get records from Airtable": {
      "main": [
        [
          {
            "node": "fn",
            "type": "main",
            "index": 0
          },
          {
            "node": "ln",
            "type": "main",
            "index": 0
          },
          {
            "node": "ct",
            "type": "main",
            "index": 0
          },
          {
            "node": "em",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code": {
      "main": [
        [
          {
            "node": "Send CAPI payload",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "em": {
      "main": [
        [
          {
            "node": "Merge2",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "fn": {
      "main": [
        [
          {
            "node": "Merge1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "ln": {
      "main": [
        [
          {
            "node": "Merge1",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "ct": {
      "main": [
        [
          {
            "node": "Merge2",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge1": {
      "main": [
        [
          {
            "node": "Merge3",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge2": {
      "main": [
        [
          {
            "node": "Merge3",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Merge3": {
      "main": [
        [
          {
            "node": "Code",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}```

One option is to modify the input for crypto function to handle all fields that needed to be encrypted:

Then all you need is to modify the hashFields node to include the fields you would like to encrypt and then you can develop all your ‘Code’ logic in the fixedHash node

1 Like

Thanks for the reply @barn4k

The Airtable node returns an array. Would you expect this approach to still work, or would some other loop logic need to be added? There was another post in this forum that applied this approach to crypto but seemed to get stuck when dealing with multiple records.

The easiest way would be to add Split in batches node right after the Airtable node and set the batch size to 1 and then link the end node to the Split node to get the loop working.

Other ways (e.g. via Code node and complicated logic to map elements) would be more complicated

1 Like

Thanks @barn4k, I’ll try that!

@barn4k I had to tweak it a little, but that works (see below). Thank you!

The last remaining thing is I want to filter out any results that have already been triggered. After the API call has been made I am doing an upset to a Google Sheet, which looks like this:

At the beginning of the workflow, right after it gets the results from Airtable, I would like to discard any results where “Quote Number” is found within the external_id column. I tried using Compare Datasets, but it seemed to expect that the data was in similar structures. Any advice?

Actually, I think I answered my own question. I resolved it by doing the filtering in JS rather than a special node.

1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.