Skip to content

Data and reporting

Deduplicate the list before it reaches a platform

One customer, four rows: a marketplace order, a WhatsApp enquiry, a form fill, and a spreadsheet somebody kept. Collapsing them is ordinary data work — normalise, compare, keep one row. What is not ordinary is what happens next. The moment that list is uploaded to an ad platform it becomes a transfer of personal data, and every platform's own documentation puts the legal basis on you, not on the tooling. Nothing in this flow establishes consent. It can only refuse to carry a row that does not have it.

Triggers
Two
Runs
Weekly, plus on write
Stack
4 tools
Durable execution
Not required

The flow

The top track keeps one row per person as records arrive. The bottom track wakes weekly and decides, per row, whether it is allowed to leave — and only what is allowed is ever hashed and sent.

Platform

A customer record arrives or changes

Sheets · Airtable

Orchestration

Normalise before comparing

n8n · Make

Data

One row per person

Sheets · Airtable

Orchestration

Every week

n8n schedule

Orchestration

Take the rows still in scope

n8n · Make

Orchestration

Consent on file for this use?

n8n IF

Platform

Hash, then upload

Meta · Google Ads

Platform

Remove them, then say why

Google Ads · Meta

Step by step

  1. 01

    A customer record arrives or changes

    Sheets · Airtable

    An order, an enquiry, a form. Record the purpose it was collected for and the date, in the same write. Reconstructing that months later is guesswork, and guesswork is not a legal basis.

  2. 02

    Normalise before comparing

    n8n · Make

    Lowercase, trim, phones to a single international format, and for Gmail addresses strip the periods and any plus-suffix. Duplicates are mostly formatting, not different people — two rows that look different collapse into one only after this step.

  3. 03

    One row per person

    Sheets · Airtable

    Merge onto the normalised identifier, keeping the earliest consent record and the most recent contact detail. Carry the purpose and the date on the row itself, so the next step can read them rather than assume them.

  4. 04

    Every week

    n8n schedule

    Weekly is deliberate. Platform audiences drift out of step with the source list in both directions — people are added, and people withdraw consent — and each direction needs its own operation, because uploading is additive and does not remove anyone. A list refreshed once at launch is a list that is wrong by the second month.

  5. 05

    Take the rows still in scope

    n8n · Make

    Drop rows past your own retention period, and rows whose recorded purpose does not cover advertising. This is the step that shrinks the list, and it is meant to.

  6. 06

    Consent on file for this use?

    n8n IF

    Read from the row, never inferred. A purchase is not consent to marketing, and an absent value is a no. The operator decides what counts as consent and how it was obtained; the workflow only enforces the decision that was already recorded.

  7. 07

    Hash, then upload

    Meta · Google Ads

    SHA-256 after normalisation, so the platform receives a hash and never the address itself. Normalising and hashing in the wrong order produces a different digest, which reads as a low match rate rather than as an error.

  8. 08

    Remove them, then say why

    Google Ads · Meta

    Withholding a row from the next upload does not take the person out of the audience already sitting on the platform — they stay targetable until membership expires. Removal is its own job, and on Google Ads a remove operation cannot share a job with create operations. Then the count and the reason go to a named owner: expired retention, purpose mismatch, consent withdrawn. A row silently dropped looks identical to a row that was never there.

What the platform and the law will not allow

The first three are the platforms' own rules on how the data may be sent and how large the list has to be. The last two are Hong Kong's, and they sit upstream of every platform rule — a list that satisfies Meta and Google can still be unlawful to have built.

  • Uploading is additive, so consent withdrawal needs its own operation. On Google Ads, remove operations cannot be mixed with create operations in the same job, and a remove_all must be the first operation in its job or the run fails. Until that job runs, a person who withdrew consent stays a targetable member of the audience.

    Google Ads API — Customer Match: get started
  • Meta requires the upload to be hashed and states the algorithm exactly: "To create audiences, you must share your data in a hashed format to maintain privacy", and "You must hash data as SHA256; we don't support other hashing mechanisms." Meta also puts ownership plainly — "As the owner of your business's data, you are responsible for creating and managing this data."

    Meta Marketing API — Customer list custom audiences
  • Google Ads requires the same: "email addresses, first names, last names, and phone numbers must be hashed using the SHA-256 algorithm before being uploaded", and for Gmail addresses the username must have periods and any plus-suffix removed first. That normalisation step is also what makes deduplication work, which is why it belongs upstream rather than at the upload.

    Google Ads API — Customer Match: get started
  • Customer Match sets both a floor and a ceiling on the list itself: "Upload at least 5,000 members to increase the chance of having enough matched, active users for targeting", and the membership_life_span "must be no more than 540" days. A small clean list can therefore be too small to target with, which is a real outcome of doing the hygiene properly.

    Google Ads API — Customer Match: get started
  • Google states the sourcing rule as policy, not guidance: "Per policy, you can only upload data that you acquired yourself (first-party). You cannot buy email lists from third parties and upload them." The consent field must be populated on upload, and data from unconsented EEA users will not be processed for ad personalisation.

    Google Ads API — Customer Match: get started
  • Under Hong Kong's PDPO, DPP3 "prohibits the use of personal data for any new purpose which is not or is unrelated to the original purpose when collecting the data, unless with the data subject's express and voluntary consent", and DPP2 requires that personal data "is not kept longer than is necessary for the fulfilment of the purpose for which the data is used". An address collected to fulfil an order is not, without more, an address you may advertise to.

    PCPD — The Personal Data (Privacy) Ordinance at a glance
  • For direct marketing specifically, Part 6A of the PDPO requires informed consent before using personal data for direct marketing or transferring it to a third party for that purpose. Consent requires "an explicit indication by the data subject", and "silence cannot constitute consent" — so an unticked box, or a row with nothing recorded against it, is a no.

    PCPD — The Personal Data (Privacy) Ordinance at a glance

When this is not worth building

Three cases where the upkeep costs more than the duplicates, and one of them is a reason to stop entirely.

  • You cannot say, for each row, what it was collected for. That is not a scheduling problem to be solved with a weekly job — it is a reason not to upload the list at all until the record exists, because the workflow can only enforce a consent decision that somebody already made and wrote down.

  • The list is small enough that one person recognises the duplicates on sight. They will merge them faster than a weekly job will, and the job becomes another place personal data is copied to for no gain.

  • The platform audiences are not actually used for targeting. Keeping a customer list in step with an audience nobody spends against means you are holding personal data on an ad platform to no end, which is exposure without a corresponding benefit.

Related reading

Talk to us

Which of these should you actually build?

We run these flows for Hong Kong operators every week. Tell us the process that is costing you, and we will say whether automating it is worth the upkeep.

Start a conversation