Convert ADF XML leads into HubSpot with Zapier

Convert ADF XML automotive leads to JSON in Zapier, then map them to HubSpot with duplicate checks, safe error handling, and a working Python example.

Oct 15, 2026
Convert ADF XML leads into HubSpot with Zapier
You can make ADF leads work in HubSpot without changing lead providers or abandoning Zapier. The key is to convert the ADF XML into JSON inside the Zap, then map the JSON fields into HubSpot records reliably.
Abstract data lines representing ADF XML leads converted to JSON and mapped into HubSpot with Zapier. Photo by Logan Voss on Unsplash
Abstract data lines representing ADF XML leads converted to JSON and mapped into HubSpot with Zapier. Photo by Logan Voss on Unsplash

What ADF is (and why it breaks in Zapier)

ADF (Auto-lead Data Format) is an XML-based format commonly used by automotive lead sources. Many lead providers deliver the ADF payload inside the body of an email.
The challenge is not that Zapier cannot process XML. It is that the email trigger may expose the payload as one text field rather than separate CRM fields. A parsing step makes the customer, vehicle, and lead metadata available for mapping.
Start with the ADF 1.0 specification, then compare real payloads from your providers. The standard is defined; provider implementations, optional fields, and email wrappers can differ.

The reliable ADF to HubSpot fix: XML → JSON inside the Zap

Keep everything in Zapier, but insert a single transformation step right after the trigger:
  1. Trigger: New email arrives with the ADF XML in the body
  2. Code step: Convert XML to JSON
  3. HubSpot: Find or create Contact
  4. HubSpot: Find or create Deal (optional)
  5. HubSpot: Update properties using the mapped fields
This preserves Zapier’s visibility (task history, troubleshooting, and simple edits) while making the payload usable for field mapping.

Step-by-step build (email → HubSpot)

1) Trigger on the inbound ADF email

Choose an email trigger that can reliably capture the raw body content.
Common patterns:
  • A dedicated inbox address that only receives ADF leads
  • A label/folder rule that routes only lead emails into the Zap trigger
The goal is to extract one field that contains the full ADF XML payload (often the email body).

2) Add a Code step to convert XML to JSON

Use Code by Zapier → Run Python, map the clean XML into an input named xml, and add the public PyPI package defusedxml through the Code step’s Packages settings. Zapier’s package documentation says third-party packages require a paid account (as of October 2026 — check current plan details).
The following example returns flat, JSON-serializable fields for one non-namespaced ADF prospect. It rejects DTDs and oversized inputs and flags a missing email for review. It is an example parser, not a complete ADF schema validator.
from defusedxml import ElementTree as ET xml_text = input_data.get("xml", "").strip() if not xml_text or len(xml_text.encode("utf-8")) > 100_000: raise ValueError("Missing XML or payload exceeds this example limit") root = ET.fromstring(xml_text, forbid_dtd=True) if root.tag != "adf": raise ValueError("Expected a non-namespaced adf root") prospects = root.findall("prospect") if len(prospects) != 1: raise ValueError("This example requires exactly one prospect") p = prospects[0] contact = p.find("customer/contact") if contact is None: raise ValueError("Missing customer/contact") def text(node, path): return (node.findtext(path) or "").strip() names = { n.get("part"): (n.text or "").strip() for n in contact.findall("name") } output = { "lead_id": text(p, "id"), "first_name": names.get("first", ""), "last_name": names.get("last", ""), "email": text(contact, "email"), "phone": text(contact, "phone"), "vehicle_vin": text(p, "vehicle/vin"), "vehicle_year": text(p, "vehicle/year"), "vehicle_make": text(p, "vehicle/make"), "vehicle_model": text(p, "vehicle/model"), "provider": text(p, "provider/name"), "request_date": text(p, "requestdate"), } output["needs_review"] = not bool(output["email"])
This example uses the first phone number and first vehicle. Extend and test the mapping if you need multiple values, full-name-only records, namespaces, or multi-prospect payloads. Do not parse XML with regular expressions.
If the trigger contains HTML, forwarded text, or MIME wrappers, extract the clean XML first. Pin and test the package version you use. Local sample tests do not substitute for a live test in your Zapier account; verify the Python input and output behavior with representative, anonymized payloads.

3) Map fields into HubSpot Contact

In HubSpot, use a “Find Contact” step first (typically by email). If no match exists, create the contact.
Typical field mapping:
  • Email → Contact email
  • First/last name → Contact name fields
  • Phone → Contact phone
  • Lead source → a custom property (or lifecycle fields, depending on your setup)

4) Create or update a Deal (if your pipeline needs it)

If your sales process tracks each lead as a deal, add a step to find or create a deal and associate it to the contact.
Decide on:
  • Deal name convention (e.g., “New Lead — {{Last Name}}, {{Vehicle Model}}”)
  • Pipeline/stage defaults
  • Owner assignment rules (round-robin, territory, or fixed owner)

5) Add guardrails so it doesn’t fail silently

ADF feeds are messy in the real world. Build lightweight error-handling so you don’t lose leads:
  • If parsing fails, retain the payload in restricted storage and alert the owner with a message ID and failure reason. Do not broadcast customer details or the complete raw email to a shared channel.
  • Use a Filter or Path for needs_review. Missing or invalid contact data should go to a review queue, not blindly create an incomplete HubSpot record.
  • Normalize contact identifiers and check existing records before creating them. A shared phone number is not proof that two people are the same.
  • Deduplicate the inquiry separately from the contact, using the provider and stable lead ID when available, plus the source email message ID for replay protection.
  • Store the resulting HubSpot IDs. Retrying an email should not create a second deal or re-trigger notifications.

Example field mapping cheat sheet

ADF defines standard elements; the fields populated by a particular provider can vary. These are common mapping targets:
  • Customer
    • Name
    • Email
    • Phone
    • Address
  • Vehicle
    • Year, make, model, trim
    • VIN (when present)
  • Lead metadata
    • Provider/source
    • Received timestamp
Keep the JSON output consistent so your HubSpot steps don’t break when optional fields are missing.

When to keep it in Zapier vs. move to a dedicated parser

For most dealerships, staying in Zapier is the fastest path because it’s visible and maintainable.
Move to a dedicated parser only when:
  • The lead volume is high enough that occasional manual fixes are too costly
  • You have multiple lead formats to support (not just ADF XML)
  • You need advanced validation or enrichment before the CRM step
Staying in Zapier also means anyone who already knows Zapier and HubSpot can maintain the workflow later, without learning a separate parser service.

Get help mapping your ADF leads into HubSpot

ADF payloads rarely match the spec exactly, and the mapping usually breaks on a provider's optional fields or email wrapper. If you want this built right and easy to maintain, book a ZoomFlow session and we'll map your real ADF payloads to the HubSpot fields you care about, live on the call.