Site catalog

LinkedIn for AI Agents

linkedin.com: 28 mapped actions across 12 screens

LinkedIn is the world's largest professional network: jobs, people, and company pages behind one login. Through Rindler, your agent drives it like an API. It can search public job listings without signing in and open postings. Signed in with your account, it can walk the Easy Apply wizard step by step, search people and companies, read your own network, open profiles, and send real connection requests, with or without a note.

The mapping covers 28 actions across 12 screens, and the core reads come back as structured records, not raw HTML for your agent to scrape.

What is mapped

The job surface runs end to end. Your agent searches public listings with search_jobs, narrows them with filter_jobs (recency codes for past day, week, or month, plus on-site, remote, or hybrid work types), pages deeper with next_page, and opens a posting with view_job. On a job it can expand the collapsed description, save the job to your My Jobs list, and later read that list back with list_saved_jobs.

For Easy Apply jobs, apply_to_job opens the wizard in place, read_application_step reports the current step and any inline validation errors, fill_contact_info fills the commonly empty phone field, and continue_application advances step by step. The flow deliberately stops at LinkedIn's Review screen (see quirks below).

The social surface needs your signed-in session. search_people searches all of LinkedIn, search_connections scopes to your own first-degree network, and search_companies finds company pages. From there your agent opens profiles with view_profile, lists a company's staff with list_company_employees, checks your own profile with view_my_profile, and sends real connection requests with connect or connect_with_note.

Signing in

Job search is public. search_jobs, filter_jobs, list_jobs, view_job, next_page, expand_description, and go_back_to_listing all work on LinkedIn's logged-out guest surface, no account needed.

The social and application surface requires a signed-in session: people and company search, profiles, connections, the feed, saving jobs, and the whole Easy Apply flow. The auth config points at linkedin.com/login, and the login action takes a username, password, and an OTP for two-step verification. The session rides LinkedIn's li_at cookie, and a capture_login flow connects your own account. If the session expires, LinkedIn redirects the feed and profile pages to its sign-in wall; actions like go_to_feed and view_my_profile detect this and report that the session needs reconnecting instead of failing silently.

Quirks worth knowing

These come straight from the mapped behavior, not guesswork:

  • **Never fabricate a job or profile URL.** Job links must come from a url returned in data.listings; profile links must come from a prior search_people or search_connections result. The guest job results page can hide every per-job link behind a sign-in interstitial, and a hand-built /jobs/view/{id} link can send you to the wrong posting. The actions enforce this rule.
  • **Guest search encoding matters.** Spaces in keywords and location must be %20-encoded, never +-encoded; a literal + silently degrades the match to a far broader result set. A contextual sign-in dialog can also cover fresh result pages; the config dismisses it automatically before reading.
  • **Pagination is infinite scroll.** next_page auto-appends roughly 10 more results via XHR. Track growth through listings_total, not the length of data.listings, which stays pinned to a preview of the first page.
  • **Irreversible writes are guarded.** submit_application is a canary: it advances to LinkedIn's Review screen and stops, never clicking Submit; you file the application yourself, or the agent calls discard_application to clean up. Likewise connect and connect_with_note send real invitations, require the member's exact display name from the profile top card, and back off when LinkedIn shows a weekly-invitation-limit dialog. Jobs that apply through an external company site are handed back to you rather than attempted.

Reading results

The core reads return structured records. Job searches land on the guest results screen and list_jobs returns rows of {title, url, location, posted}. People searches return {name, profile_url, headline}; on search_connections, genuine first-degree connections carry a 1st marker in the headline, and the config tells agents to exclude LinkedIn's mixed-in suggested profiles. Company search returns {name, company_url, summary} with an industry, location, and size line, and view_company surfaces the HQ, follower line, and size band. Saved jobs come back as {title, url, meta}, where each url feeds directly into view_job and meta is a single text line packing company, location, posted age, and apply type that your agent parses out itself.

Behind those reads sit dedicated screens for the job detail page, the Easy Apply wizard, profile detail, company pages, people and company search, saved jobs, and the feed, so the agent always knows which surface it is on.

Example session

start_session(url: "https://www.linkedin.com")
# guest job search: no sign-in required
dispatch_action(action: "search_jobs",
                params: {"keywords": "...", "location": "..."})
# open a posting using a url returned in data.listings (never hand-built)
dispatch_action(action: "view_job", params: {"job_url": "..."})
dispatch_action(action: "expand_description")
close_session()

Every mapped action

Generated from the live site config. 19 of 28 actions require a signed-in session.

ActionWhat it does
apply_to_jobauthBegin an Easy Apply application for the currently-open LinkedIn job. Requires a logged-in session. FIRST distinguish the apply type: this action ONLY works for Easy Apply jobs, whose control is role=link[name='Easy Apply to this job' (standalone page) or a button named 'Easy Apply to {title} at {company}' (SERP pane). If instead you see role=link[name*='on company website'] (visible text 'Apply') or the text 'Responses managed off LinkedIn', the job uses EXTERNAL apply: it hands off to a third-party ATS outside LinkedIn and is NOT supported here. Hand such jobs back to the user; do not attempt to apply. On an Easy Apply job this opens the wizard dialog in place (the URL stays on /jobs/view/{id}/). After it opens, call read_application_step to see the first step, then fill the fields and advance with continue_application. Nothing is submitted until submit_application, which this seed deliberately stops short of (see its description).
capture_login
connectauthSend a LinkedIn connection request (without a note) to the member whose profile is currently open. Pass member_name = the member's display name EXACTLY as shown in the profile top card (e.g. 'Aamir P.'); it scopes the Connect control to that person and excludes the sidebar 'People also viewed' duplicates. Requires a logged-in session; call view_profile first. This sends a real, irreversible invitation. If the profile offers only Follow (no Connect), or LinkedIn shows an email-verification or weekly-invitation-limit dialog, report it to the user rather than retrying. LinkedIn caps invitations (~a weekly limit), so large batches are eventually blocked.
connect_with_noteauthSend a LinkedIn connection request WITH a short note to the member whose profile is currently open. Pass member_name = display name EXACTLY as in the profile top card (scopes the Connect control and excludes sidebar duplicates) and note = the message (<= 300 chars). Requires a logged-in session; call view_profile first. This sends a real, irreversible invitation. For a note-less invite use `connect`. If only Follow is offered, or an email-verification or weekly-invitation-limit dialog appears, report it to the user rather than retrying.
continue_applicationauthAdvance the Easy Apply wizard to the next step by clicking 'Continue to next step' (visible text 'Next'). Call this after filling the current step's fields. If there is no Continue button you are on the final form step before Review (call submit_application, which advances to the Review step and stops) or the advance was blocked by a validation error (call read_application_step to read the inline alert and fix the field). The wizard dialog stays on /jobs/view/{id}/.
discard_applicationauthDiscard the in-progress Easy Apply draft and close the wizard without applying. Clicks the wizard Dismiss (X) and then 'Discard' in the 'Save this application?' confirmation (NOT 'Save', which would keep a resumable draft). The page returns to the job view with the Easy Apply control restored. Call this to clean up after reviewing an application you do not intend to submit.
expand_descriptionExpand the collapsed job description on a job detail page by clicking the Show more button. The description is collapsed by default; the collapsed ARIA tree still contains substantial description text, so call this only when the full text is needed. If the description is already expanded (button absent), the action still succeeds as a no-op.
fill_contact_infoauthFill the Contact info step of the Easy Apply wizard. Most fields (first/last name, email, phone country code) are pre-filled from the LinkedIn profile; the one field commonly empty and required is the mobile phone number, which this action fills. Provide phone (a valid-format number) or accept the safe default. Call read_application_step first to confirm you are on the Contact info step, then continue_application to advance. If the phone field is absent for this job the action no-ops.
filter_jobsSearch jobs with LinkedIn's guest filters applied via URL params. Combine keywords/location with date_posted (LinkedIn recency code: r86400 = past 24h, r604800 = past week, r2592000 = past month) and/or work_type (LinkedIn code: 1 = on-site, 2 = remote, 3 = hybrid). Omitted filters are dropped automatically. Results land in data.listings just like search_jobs; the same rule applies -- only use the url values in data.listings, and if it is empty or a listing has no url, report the titles and search-page URL rather than constructing a /jobs/view/{id} link.
go_back_to_listingReturn to the job search results from a job detail page.
go_to_feedauthOpen the signed-in user's LinkedIn home feed (the /feed/ page). Requires a logged-in session. Lands on the `feed` screen. NOTE: on a logged-out or expired session LinkedIn redirects /feed/ to its sign-in page; if the page shows a sign-in form rather than the feed, the session needs to be (re-)connected via the Connect sign-in flow before the feed is readable.
list_company_employeesauthFrom a company page, list employees by jumping to the people search filtered to that company. Pass the company's numeric id (from the 'employees' link on the company page, e.g. currentCompany=2135371). Results land in data.listings like search_people.
list_jobsSettle the search results and return the current job listings. data.listings is an array of {title, url, location, posted} records -- use those directly. Only fall back to extract_content if data.listings is empty when jobs are expected. If data.listings is empty or a record has no url (the logged-out SERP can show job titles while a sign-in interstitial hides every per-job link from the page, and extract_content then returns extraction_empty=true), report the visible titles/companies and the search-page URL, and NEVER construct, guess, or reuse a https://www.linkedin.com/jobs/view/{id} URL you did not receive in data.listings -- a fabricated job link sends the user to the wrong posting.
list_saved_jobsauthRead the saved jobs list. data.listings is an array of {title, url, meta} -- title and url come from the card's title link (url is a /jobs/view/{id}/ link usable with view_job); meta is one unstructured text blob holding company, location, posted-age and apply-type that you must parse out yourself. Call view_saved_jobs first to land on the page. Fall back to extract_content only if data.listings is empty when saved jobs are expected.
loginSign in to LinkedIn with email and password.
next_pageLoad more results on a job search results page. LinkedIn guest pagination is infinite scroll: the initial load contains 60 result cards and scrolling to the bottom auto-appends batches of roughly 10 more via XHR. There is no Next button and no page-number links; a See more jobs button is known to exist when auto-load pauses but was never observed in the recon, so do not rely on it. After calling this, call list_jobs and compare listings_total (NOT the length of data.listings, which is capped at a small preview near the top of the result set and will not grow) to the previous read to detect growth; if listings_total stops growing across repeated calls, the result set is exhausted. The data.listings records themselves stay pinned to the first page and do not change after next_page -- only listings_total reflects how many have actually loaded.
read_application_stepauthRead the current Easy Apply wizard step without changing anything. Returns the step title (Contact info / Resume / Work experience / Education / Additional Questions / Review your application), any required questions, and any inline validation errors (e.g. 'Enter a valid phone number', 'A resume is required'). Call this after apply_to_job and after each continue_application to decide what to fill next. The wizard dialog stays on /jobs/view/{id}/ the whole time.
save_jobauthSave (bookmark) the currently-open LinkedIn job to the signed-in account's My Jobs > Saved list. Requires a logged-in session. Call this only on a job_detail page reached via view_job. The job is saved when the Save button (role=button[name='Save the job']) flips to Unsave (role=button[name='Unsave the job'], visible text 'Saved') and a 'You''ve saved this job.' toast appears. If the job is already saved the Save button is absent and this action is a harmless no-op. Saved jobs can later be listed with list_saved_jobs.
search_companiesauthSearch LinkedIn companies by keyword (requires a logged-in session). Results land in data.listings as {name, company_url, summary} -- summary holds the industry/location/size line. Use view_company to open one. Note: LinkedIn's company search legitimately returns meetup/event pages as Company results; filter to actual companies by checking the industry/category portion of each result's summary line.
search_connectionsauthSearch the SIGNED-IN user's OWN first-degree LinkedIn connections (people they are directly connected to). Use THIS action, not search_people, whenever the user asks about my connections, people I know, my network, or who among my connections is/does X. search_people searches ALL of LinkedIn (strangers); this is scoped to the user's own connections only. Both params are optional: keywords narrows connections by name, title, company, or location text (e.g. keywords=New York to surface connections based in New York, keywords=product manager for connections in that role, or combine them: product manager New York); leave keywords empty to list ALL connections. page (1, 2, 3, ...) pages through more results (about 10 per page); omit for the first page. Results land in data.listings as {name, profile_url, headline}; headline is the raw people-card text line, which usually runs together the connection-degree marker, the person's CURRENT role/company, their LOCATION, and a connection count -- read the role and location out of it to report who is based in a given city. CRITICAL -- report ONLY people that actually appear in data.listings, using the exact name and profile_url from each row: NEVER invent, guess, add, or embellish a person, and never report a name you did not receive in data.listings (a person not in data.listings is not a result). This surface can ALSO include LinkedIn 'People you may know' / suggested profiles that are NOT the user's connections; a genuine first-degree connection's headline carries a first-degree marker (it starts with '1st', e.g. '• 1st'), so report ONLY rows whose headline shows the 1st-degree marker and treat rows marked 2nd or 3rd (or with no degree marker) as suggestions to EXCLUDE. If a result's location is not clear from its headline, open it with view_profile to confirm rather than guessing. If data.listings comes back empty (or after excluding non-1st-degree rows nothing remains), tell the user you could not retrieve matching connections -- the session may be signed out (ask them to reconnect) or no connections match the keyword (broaden or drop it and retry); do NOT fill the answer with invented or non-connection names. Requires a logged-in session.
search_jobsSearch LinkedIn's public (logged-out) job listings by keyword and location. Navigates to the guest job-search results. Read the results from data.listings (an array of {title, url, location, posted}); job URLs are https://www.linkedin.com/jobs/view/{id}. Use view_job to open one. Only use the url values returned in data.listings: if data.listings is empty or a listing has no url, NEVER construct, guess, or reuse a /jobs/view/{id} URL (a fabricated link sends the user to the wrong posting); report the visible titles and the search-page URL instead. Guest caveats (2026-06-10 recon, linkedin.md Quirks 1 and 3): spaces in keywords/location must be %20-encoded, never +-encoded (a literal + in the query silently degrades the match, e.g. 3,933,000+ results instead of 133,000); and on fresh loads a contextual sign-in dialog can cover the page and hide everything else from the accessibility tree (data.listings comes back empty), so it must be dismissed (role=button[name='Dismiss'], handled by the interrupt_handlers entry) before any snapshot-based read.
search_peopleauthSearch LinkedIn people by keyword (requires a logged-in session). Results land in data.listings as {name, profile_url, headline} -- name is the person's name, headline holds their role/headline line (it may also carry their location). Use view_profile to open one. Report ONLY people that appear in data.listings, using their exact name and profile_url; NEVER invent, guess, or report a person who is not in the results, and if data.listings is empty say so rather than naming anyone. To search the signed-in user's OWN connections (their network, i.e. my connections) rather than all of LinkedIn, use search_connections instead, which scopes results to first-degree connections only.
submit_applicationauthCANARY ONLY: advance the Easy Apply wizard to the final Review step and STOP. This action deliberately does NOT submit the application. It clicks 'Review your application' on the last form step and confirms the Review screen (heading 'Review your application', with the 'Submit application' button present but UNCLICKED). Filing a real application cannot be undone, so Rindler never clicks Submit on the user's behalf; the user must submit manually outside Rindler after reviewing. After this, either leave the draft (LinkedIn auto-saves answers) or call discard_application to discard it. Do not expect a confirmation/thank-you page from this action; reaching Review IS success.
view_companyauthOpen a LinkedIn company page by slug or URL (requires a logged-in session). data.listing carries the HQ + follower line and the size band; the company name is the slug you passed.
view_jobOpen a LinkedIn job detail page by URL. Obtain job_url ONLY from a url returned in list_jobs / data.listings. If data.listings was empty (the guest SERP can hide every per-job link behind a sign-in interstitial, in which case extract_content returns extraction_empty=true), do NOT call view_job: never fabricate, guess, or hand-build a /jobs/view/{id} URL you did not receive in data.listings. Shows the full description and (for guests) a sign-in-gated apply button.
view_my_profileauthOpen the signed-in user's OWN LinkedIn profile page. Requires a logged-in session. No profile URL is needed: this navigates to LinkedIn's self-alias /in/me/, which redirects to the logged-in member's own profile. Lands on profile_detail; the member's name and headline are in the page's top card (read via extract_content / raw ARIA). NOTE: on a logged-out or expired session /in/me/ redirects to a Join/sign-in wall; if the page shows 'Join LinkedIn' rather than a profile, the session needs to be (re-)connected first.
view_profileauthOpen a LinkedIn member profile by URL (requires a logged-in session). Use ONLY a profile_url that appeared in a prior search_people / search_connections data.listings row; NEVER fabricate, guess, or hand-build a /in/ profile URL, and do not open a profile for a person who was not in data.listings.
view_saved_jobsauthOpen the signed-in account's saved jobs list (My Jobs > Saved). Requires a logged-in session. Lands on the saved-jobs page; call list_saved_jobs to read the saved postings as data.listings ({title, url, meta}). The url of each is a /jobs/view/{id}/ link you can pass to view_job.

Screens and structured records

  • company_page returns structured fields records
  • company_search returns structured fields, _comment, container records
  • easy_apply_wizard returns structured fields, _comment, container records
  • feed (navigation screen)
  • job_detail returns structured fields, _comment records
  • job_listing returns structured fields, _comment, container records
  • job_search_results_guest returns structured fields, _comment, container records
  • jobs_home_guest returns structured fields, _comment, container records
  • landing (navigation screen)
  • people_search returns structured fields, _comment, container records
  • profile_detail (navigation screen)
  • saved_jobs returns structured fields, _comment, container records