LinkedIn export contact import
Use this skill when you've downloaded your LinkedIn data export and want your connections, sent invites and DM history in your CRM or contact sheet. Produces upserted contacts plus dated touches, safe to re-run every week. "Import my LinkedIn export", "load my connections into the CRM", "who have I messaged on LinkedIn".
Applies when LinkedIn holds relationship history your CRM doesn't. Produces contacts from Connections and sent invitations, and one dated touch per one-to-one message, deduplicated so weekly re-imports add only what's new.
No scraping and no API: this works on the export LinkedIn gives every member.
The play
- Request the export from LinkedIn's data privacy settings. The basic export has Connections, Invitations and messages. The complete one adds comments, shares and reactions. A weekly rhythm that works: basic midweek, complete at the weekend.
- Unzip each export into its own dated folder. Never overwrite the previous one.
- Read
Connections.csvfrom the line that startsFirst Name,Last Name,. LinkedIn puts notes above the header. - Key every person on the
/in/part of their profile URL. A name-only match is a candidate: list it for the human to confirm. - Contacts come from Connections, plus OUTGOING rows from
Invitations.csv. Count and skip members whose fields are all blank (hidden or deactivated). - From
messages.csv, keep only one-to-one threads. Skip drafts, spam and group threads. Each message becomes a touch: date, person, channel, direction. - Dry run first. Show the proposed creates, merges and updates; apply only after the human approves.
- Change a contact's status only from recent messages: within 60 days of the newest message in the export. Import exports in date order and never one older than the last. A two-year-old thread is history, not a live conversation.
The file-by-file quirks are in references/export-file-notes.md. Open it before writing the parser.
What good looks like
- First check: a second run of the same export adds zero touches. If it adds any, the dedupe key is wrong.
- The mediocre version imports everything as current. Old threads flip contacts to "in conversation", group chats become replies, and drafts you never sent count as messages.
- The output is right when the counts reconcile: Connections rows equal new plus matched plus skipped-blank, and five spot-checked people show the right last message date.
Rules
- MUST dry run before writing, and keep each export folder intact.
- MUST key on the profile URL slug; NEVER merge two people on name alone when more than one contact has that name.
- NEVER treat a draft, spam or group message as a touch.
- NEVER use an old export to downgrade data a newer one wrote.
- NEVER upload the export to a third-party service to parse it; it contains other people's messages.
references/export-file-notes.md
Export file notes
Which file gives what
| File | In basic | Use | Watch for |
|---|---|---|---|
Connections.csv | yes | name, profile URL, company, position, email (rarely), Connected On | notes above the header; hidden members are blank except Connected On |
Invitations.csv | yes | invites you sent | keep rows whose Direction is OUTGOING; the message column is your note |
messages.csv | yes | DMs | drafts (IS MESSAGE DRAFT), a SPAM folder, group threads |
Comments_<id>.csv | complete only | your comments on others' posts | none of the basic export's people data |
Shares_<id>.csv, Reactions_<id>.csv | complete only | your posts and reactions | not needed for contacts |
Parsing
- Header. Find the line starting
First Name,Last Name,and read from there. Hard-coding "skip 3 lines" works until LinkedIn edits the note. - Dates differ between files. Seen across the export:
30 Jul 2026,2026-07-31 20:19:20 UTC,7/29/26, 1:59 PM,5/19/2026 2:06:34. Try each format explicitly; don't let a parser guess day versus month. - Spaces. The basic and complete exports encode the same visible space differently (non-breaking spaces in one). Normalize whitespace before comparing names or text, or the same row imports twice.
- Group threads. A thread is one-to-one when it has exactly one participant besides you.
Dedupe
- One touch per person, channel, direction and day. Re-importing the same export must add nothing.
- A person's key: the profile URL slug. An exact name that matches one contact is only a candidate; list it for confirmation.
First import versus weekly
- First import is a backfill. Nothing in it is "newly accepted": there's no previous export to compare against. Don't trigger follow-ups from it.
- Weekly, compare against the last export to find newly accepted invitations and new messages.
- Apply the 60-day rule for status changes: only messages within 60 days of the export's newest message can move someone to "in conversation".
The common failure
The export gets downloaded and sits in a folder. Make the import a step of the weekly routine that checks for a newer export first, rather than waiting for someone to remember.