DEV Community

Daniel Meshulam
Daniel Meshulam

Posted on

BrassRing has a JSON job search, and Home Depot publishes 23,982 jobs through it

Best Buy's careers site is a ServiceNow portal. Its apply links go somewhere
else: sjobs.brassring.com, which is BrassRing (Infinite Talent, once IBM
Kenexa). One host serves every employer on it, and a board is a partner id
plus a site id:

https://sjobs.brassring.com/TGnewUI/Search/Home/Home?partnerid=25632&siteid=5649
Enter fullscreen mode Exit fullscreen mode

That one is Best Buy. Home Depot's store jobs are 25526/5032, Walgreens
26336/5014. There is no robots.txt on the host (404), and the search the page
itself calls is plain JSON.

The two calls

The search page carries an anti-forgery token, and the Ajax calls want it as a
header named RFT. Without it every call is HTTP 500 with an HTML error page,
which is what makes this look closed when it is not.

import re, requests

s = requests.Session()
home = s.get("https://sjobs.brassring.com/TGnewUI/Search/Home/Home",
             params={"partnerid": "25632", "siteid": "5649"},
             headers={"User-Agent": "Mozilla/5.0"}).text
token = re.search(r'name="__RequestVerificationToken"[^>]*value="([^"]+)"', home).group(1)
H = {"RFT": token, "X-Requested-With": "XMLHttpRequest",
     "Content-Type": "application/json", "User-Agent": "Mozilla/5.0"}

first = s.post("https://sjobs.brassring.com/TgNewUI/Search/Ajax/MatchedJobs", headers=H, json={
    "PartnerId": "25632", "SiteId": "5649", "Keyword": "", "Location": "",
    "KeywordCustomSolrFields": "JobTitle,Location", "LocationCustomSolrFields": "Location",
    "FacetFilterFields": None, "TurnOffHttps": False, "Latitude": 0, "Longitude": 0,
    "PowerSearchOptions": {"PowerSearchOption": []}, "encryptedsessionvalue": ""}).json()

first["JobsCount"]                      # 2684
len(first["Jobs"]["Job"])               # 50
Enter fullscreen mode Exit fullscreen mode

A job arrives as a list of question/value pairs rather than an object:

{q["QuestionName"]: q["Value"] for q in first["Jobs"]["Job"][0]["Questions"]}
# {'reqid': '3761989', 'jobtitle': 'Retail Sales Associate',
#  'lastupdated': '22-Sep-2026', 'formtext12': 'Greensboro',
#  'formtext10': 'North Carolina ', 'formtext1': 'Part time ', ...}
Enter fullscreen mode Exit fullscreen mode

Pages come from a different endpoint, ProcessSortAndShowMoreJobs, whose keys
are lower-cased (partnerId, pageNumber). PageNumber on MatchedJobs
looks like it pages and does not.

The trap: the sort repeats pages

A site offers two sorts, date and title, and both are full of ties, so
consecutive pages overlap and skip. Sweeping Best Buy's 54 pages once by date
returned 2,299 distinct jobs of 2,680. Not a rate limit, not an error: just an
unstable sort under a paging API.

What works is sweeping more than once and joining on the requisition id:

date sweep                 2,299
title sweep                2,580
date + title + date        2,661   (99.3%)
Enter fullscreen mode Exit fullscreen mode

Stop as soon as the union reaches the declared count, and most sites finish in
one sweep. Read that way, live on 2026-09-22: Best Buy 2,684 of 2,684 in 44
seconds, Performance Food Group 1,359 of 1,359, Home Depot 23,876 of 23,982 in
1,441 requests.

Which fields hold the place changes per site

The page config says what each site shows under a title:

"JobFieldsToDisplay": {"JobTitle": "jobtitle",
                       "Position3": ["formtext12", "formtext10", "formtext1"],
                       "Summary": "jobdescription"}
Enter fullscreen mode Exit fullscreen mode

Best Buy shows city, state and schedule in custom fields. Home Depot has a
location field and uses it. Performance Food Group shows its division, then
"St Louis, Missouri (MO)", then a facility name, and its location field
holds the facility. Edward Jones shows the requisition number first, and
TeamHealth shows a medical specialty and no place at all.

A rule that survives all of those: prefer a shown value that reads as "City,
State"; else the site's own location; else join the shown values up to the
one naming a state, skipping ids and anything with a colon; and if none of
them names a state, publish no location rather than a wrong one.

How many employers are on it

The Wayback CDX index lists archived search pages: 727 partner/site pairs, 489
of which still answer, 120 with open roles. After dropping internal-only
sites, a template site and a network that re-posts other employers' jobs, 98
boards and 72,436 jobs, including Home Depot's stores (23,982), Walgreens
(22,446), Best Buy, Harbor Freight, Infosys, Performance Food Group, Hobby
Lobby, GardaWorld, ADM, Edward Jones, Publix, American Greetings, Bechtel,
GUESS, AAFES, U.S. Steel and Stantec.

One more thing worth knowing: an employer runs several sites over one partner
id (ADM in six languages, Edward Jones three, Walgreens two), and the same
requisition appears on more than one. The requisition is keyed per partner, so
partner + reqid is the job.


If you want the rows rather than the code, that is what
ats-jobs-scraper does: a
company name in, every open posting out, from BrassRing and twenty other
career systems, as JSON.

Top comments (0)