
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
@cardog/adf
Advanced tools
The definitive ADF (Auto-lead Data Format) parser and builder for automotive leads — parse and create ADF XML for dealer CRMs
The definitive TypeScript library for parsing and building ADF (Auto-lead Data Format) — the automotive industry's standard XML format for exchanging lead data between dealerships, CRMs, and lead providers.
AdfLead structure for easy integrationnpm install @cardog/adf
# or
pnpm add @cardog/adf
# or
yarn add @cardog/adf
import { parse, parseOne } from "@cardog/adf";
const xml = `<?xml version="1.0"?>
<?adf version="1.0"?>
<adf>
<prospect status="new">
<requestdate>2024-03-15T10:30:00Z</requestdate>
<vehicle interest="buy" status="used">
<year>2024</year>
<make>Tesla</make>
<model>Model 3</model>
<vin>5YJ3E1EA5PF123456</vin>
</vehicle>
<customer>
<contact>
<name part="first">John</name>
<name part="last">Doe</name>
<email>john@example.com</email>
<phone type="cellphone">416-555-1234</phone>
</contact>
</customer>
<provider>
<name>AutoTrader</name>
</provider>
</prospect>
</adf>`;
// Parse single lead
const lead = parseOne(xml);
console.log(lead.firstName); // "John"
console.log(lead.email); // "john@example.com"
console.log(lead.vehicleMake); // "Tesla"
console.log(lead.provider); // "AutoTrader"
// Parse multiple prospects
const result = parse(xml);
console.log(result.success); // true
console.log(result.leads); // AdfLead[]
console.log(result.errors); // string[]
import { build } from "@cardog/adf";
const xml = build(
{
firstName: "John",
lastName: "Doe",
email: "john@example.com",
cellphone: "416-555-1234",
vehicleMake: "Tesla",
vehicleModel: "Model 3",
vehicleYear: "2024",
vehicleVin: "5YJ3E1EA5PF123456",
vehiclePrice: 55000,
vehiclePriceCurrency: "CAD",
},
{
vendor: "Your Dealership",
provider: "Your Website",
},
);
import { validate } from "@cardog/adf";
const result = validate(xml);
console.log(result.valid); // boolean
console.log(result.errors); // string[]
ADF (Auto-lead Data Format) is an XML-based industry standard for transmitting automotive leads. Developed in the late 1990s by a consortium of 13 automotive internet companies, ADF has become the universal format supported by virtually every dealer CRM, lead provider, and automotive marketplace.
| Attribute | Value |
|---|---|
| Version | 1.0 (released May 2000) |
| Format | XML with optional DTD validation |
| Encoding | UTF-8 (recommended) |
| Transmission | Email attachment or HTTP POST |
| Specification | adfxml.info/adf_spec.pdf |
Lead Providers:
CRM Systems:
An updated specification (ADF 2.0) has been proposed with additional elements for chat transcripts, sensitive data URLs, and service/parts leads, but ADF 1.0 remains the dominant standard.
<?xml version="1.0" encoding="UTF-8"?>
<?adf version="1.0"?>
<adf>
<prospect status="new">
<requestdate>2024-03-15T10:30:00Z</requestdate>
<vehicle interest="buy">
<year>2024</year>
<make>Tesla</make>
<model>Model 3</model>
</vehicle>
<customer>
<contact>
<name part="full">John Doe</name>
<email>john@example.com</email>
</contact>
</customer>
</prospect>
</adf>
adf
└── prospect # One or more lead records
├── @status # "new" | "resend"
├── id # Unique identifier
│ └── @sequence, @source
├── requestdate # ISO 8601 timestamp
├── vehicle[] # One or more vehicles
│ ├── @interest # "buy" | "lease" | "sell" | "trade-in" | "test-drive"
│ ├── @status # "new" | "used" | "certified"
│ ├── id
│ ├── year
│ ├── make
│ ├── model
│ ├── trim
│ ├── vin
│ ├── stock
│ ├── bodystyle
│ ├── doors
│ ├── transmission # "automatic" | "manual" | "CVT"
│ ├── condition
│ ├── colorcombination
│ │ ├── interiorcolor
│ │ └── exteriorcolor
│ ├── price
│ │ ├── @type # "asking" | "offer" | "msrp" | "invoice" | "appraisal"
│ │ ├── @currency # ISO 4217 code (CAD, USD)
│ │ └── @delta, @relativeto, @source
│ ├── odometer
│ │ ├── @status # "actual" | "estimated" | "not-actual"
│ │ └── @units # "km" | "mi"
│ ├── option[]
│ ├── finance
│ │ ├── method # "finance" | "lease" | "cash"
│ │ └── balance
│ ├── pricecomments
│ ├── comments
│ └── imageurl / imagetag
├── customer
│ ├── contact
│ │ ├── @primarycontact # "1" for primary
│ │ ├── name[]
│ │ │ ├── @part # "first" | "middle" | "last" | "suffix" | "full"
│ │ │ └── @type # "individual" | "business"
│ │ ├── email[]
│ │ │ └── @preferredcontact # "1" if preferred
│ │ ├── phone[]
│ │ │ ├── @type # "phone" | "cellphone" | "fax" | "pager" | "voice"
│ │ │ └── @time # "morning" | "afternoon" | "evening" | "day" | "nopreference"
│ │ └── address[]
│ │ ├── @type # "home" | "work" | "delivery"
│ │ ├── street[]
│ │ │ └── @line # Line number for multi-line
│ │ ├── apartment
│ │ ├── city
│ │ ├── regioncode # Province/State code (ON, CA, NY)
│ │ ├── postalcode
│ │ └── country
│ ├── comments
│ └── timeframe
│ ├── description # "immediate" | "day" | "week" | "month" | "year"
│ ├── earliestdate
│ └── latestdate
├── vendor # The dealership
│ ├── @id
│ ├── id
│ ├── vendorname
│ ├── url
│ └── contact # Same structure as customer/contact
└── provider # The lead source
├── @id
├── id
├── name
├── service
├── url
├── email
├── phone
└── contact
The normalized, flattened lead structure returned by parse() and parseOne():
interface AdfLead {
// === Source Information ===
id?: string; // Unique lead identifier
requestDate?: Date; // When the lead was submitted
status: ProspectStatus; // "new" | "resend"
provider?: string; // Lead source name (AutoTrader, CarGurus)
providerService?: string; // Service type
vendor?: string; // Dealership name
// === Contact Information ===
firstName?: string;
middleName?: string;
lastName?: string;
fullName?: string; // Computed or from part="full"
email?: string; // Primary email
phone?: string; // Primary phone
cellphone?: string; // Mobile phone
address?: {
street?: string;
city?: string;
state?: string; // Mapped from regioncode
postalCode?: string;
country?: string;
};
// === Vehicle of Interest ===
vehicleInterest?: VehicleInterest; // "buy" | "lease" | "sell" | "trade-in" | "test-drive"
vehicleStatus?: VehicleStatus; // "new" | "used" | "certified"
vehicleYear?: string;
vehicleMake?: string;
vehicleModel?: string;
vehicleTrim?: string;
vehicleVin?: string;
vehicleStock?: string;
vehiclePrice?: number; // Parsed numeric value
vehiclePriceCurrency?: string; // "CAD" | "USD"
vehicleOdometer?: number; // Parsed numeric value
vehicleOdometerUnits?: string; // "km" | "mi"
vehicleExteriorColor?: string;
vehicleInteriorColor?: string;
// === Trade-In (if present) ===
tradeIn?: {
year?: string;
make?: string;
model?: string;
vin?: string;
odometer?: number;
condition?: string;
};
// === Additional ===
comments?: string; // Vehicle comments
customerComments?: string; // Customer message
financeMethod?: string; // "finance" | "lease" | "cash"
timeframe?: string; // Purchase timeframe
// === Raw Data ===
raw: {
prospect: AdfProspect; // Full parsed prospect
xml?: string; // Original XML
};
}
<?xml version="1.0" encoding="UTF-8"?>
<?ADF VERSION="1.0"?>
<adf>
<prospect status="new">
<requestdate>2024-03-18T16:45:00Z</requestdate>
<vehicle interest="buy" status="used">
<id sequence="1" source="AutoTrader.ca">AT-98765</id>
<year>2024</year>
<make>Hyundai</make>
<model>IONIQ 5</model>
<vin>KM8KRDAF3NU123456</vin>
<price type="asking" currency="CAD">54995</price>
</vehicle>
<customer>
<contact primarycontact="1">
<name part="first">David</name>
<name part="last">Williams</name>
<email>david@example.com</email>
<phone type="cellphone">416-555-1234</phone>
</contact>
<comments>Is this vehicle still available?</comments>
</customer>
<vendor>
<vendorname>Your Dealership</vendorname>
</vendor>
<provider>
<name part="full">AutoTrader.ca</name>
<service>New Lead Notification</service>
</provider>
</prospect>
</adf>
<?xml version="1.0"?>
<?adf version="1.0"?>
<adf>
<prospect status="new">
<vehicle interest="buy" status="new">
<year>2025</year>
<make>Tesla</make>
<model>Model Y</model>
</vehicle>
<vehicle interest="trade-in" status="used">
<year>2020</year>
<make>Honda</make>
<model>Civic</model>
<vin>2HGFC2F59LH123456</vin>
<odometer units="km">85000</odometer>
<condition>Good</condition>
</vehicle>
<customer>
<contact>
<name part="full">Jane Smith</name>
<email>jane@example.com</email>
</contact>
</customer>
</prospect>
</adf>
<?ADF VERSION="1.0"?> processing instructionimagetag element for vehicle photosdelta, relativeto, sourcetype="voice" instead of type="phone"<?adf version="1.0"?> processing instructionstreet line="1" attribute for multi-line addressesparse(xml: string): ParseResultParse ADF XML into normalized leads.
interface ParseResult {
success: boolean; // True if no errors
leads: AdfLead[]; // Normalized leads
errors: string[]; // Error messages
document?: AdfDocument; // Raw parsed document
}
parseOne(xml: string): AdfLead | nullParse ADF XML and return the first lead, or null if parsing fails.
validate(xml: string): { valid: boolean; errors: string[] }Validate ADF XML structure without normalizing.
build(lead: Partial<AdfLead>, options?: BuildOptions): stringBuild ADF XML from a lead object.
interface BuildOptions {
xmlDeclaration?: boolean; // Include <?xml ...?> (default: true)
adfPi?: boolean; // Include <?adf version="1.0"?> (default: true)
pretty?: boolean; // Pretty print (default: true)
vendor?: string; // Default vendor name
provider?: string; // Default provider name
providerService?: string; // Default service name
}
buildFromProspect(prospect: Partial<AdfProspect>, options?: BuildOptions): stringBuild ADF XML from a raw prospect structure (advanced use).
For advanced use cases, the XML parser is exposed:
import {
parseXml,
findChild,
findChildren,
getChildText,
getAttr,
} from "@cardog/adf";
import type { XmlNode } from "@cardog/adf";
const root = parseXml(xml);
const prospect = findChild(root, "prospect");
const vehicles = findChildren(prospect, "vehicle");
const year = getChildText(vehicles[0], "year");
const status = getAttr(vehicles[0], "status");
Contributions are welcome! If you encounter an ADF format from a provider that doesn't parse correctly, please open an issue with a sample (with personal info redacted).
MIT - see LICENSE
Built by Cardog
FAQs
The definitive ADF (Auto-lead Data Format) parser and builder for automotive leads — parse and create ADF XML for dealer CRMs
We found that @cardog/adf demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.