Review housing marketing for discrimination risk before it ships: scan listing copy, photos, scripts and ad targeting against the Fair Housing Act advertising rule with the bundled scanner, work passage-linked findings by protected class, check Meta and Google housing targeting limits, handle the older persons exemption and local source of income law, and rewrite flagged copy into neutral property facts that keep the selling points. Use when reviewing a rental or sales listing, a housing ad campaign, a flyer, a showing script, listing photos, or platform targeting settings.
./install.sh fair-housing-marketing-reviewname: "fair_housing_marketing_review" description: "Review housing marketing for discrimination risk before it ships: scan listing copy, photos, scripts and ad targeting against the Fair Housing Act advertising rule with the bundled scanner, work passage-linked findings by protected class, check Meta and Google housing targeting limits, handle the older persons exemption and local source of income law, and rewrite flagged copy into neutral property facts that keep the selling points. Use when reviewing a rental or sales listing, a housing ad campaign, a flyer, a showing script, listing photos, or platform targeting settings."
Housing ads carry a legal rule most marketing does not: under 42 USC 3604(c) it is unlawful to publish a notice, statement or advertisement for the sale or rental of a dwelling that indicates any preference, limitation or discrimination based on race, color, religion, sex, handicap, familial status, or national origin. HUD's regulation at 24 CFR 100.75 applies the same rule to photographs, illustrations and symbols, to things said to agents and prospects, and to choosing media or locations that keep part of the market from learning a home exists. Courts judge the wording by the ordinary reader test: what a normal reader would take from it, not what the writer meant.
This skill runs that review as a workflow with tooling. scripts/scan_copy.py scans copy for flagged phrases and checks a JSON record of campaign targeting settings against the Meta and Google housing rules. The scanner starts the review. The human read in the workflow finishes it, because context is where most of these calls are decided.
Scope: this skill covers US federal law and the two big ad platforms, plus the local law checks that change the answer. It is a review workflow, not legal advice and not a clearance. Anything genuinely contested goes to counsel with the review record attached.
Collect the full set before reviewing any of it:
A phrase fixed in the listing and left live in the feed, the flyer or the chatbot is still published. Review the set as one thing.
The federal list is race, color, religion, sex, handicap (disability), familial status and national origin. HUD's April 2024 digital advertising guidance reads sex to include sexual orientation and gender identity, and reads familial status to cover children under 18 in the home, pregnancy, and a person securing legal custody of a child.
State and local law adds classes that change real answers: source of income, age outside the older persons exemption, marital status, sexual orientation and veteran or military status are common additions, and the list differs by state and city. Pull the current list for the property's jurisdiction from the state or local fair housing agency and write it at the top of the review record. Two scanner flags depend on it:
--soi-protected where source of income is protected. It turns no Section 8 and no vouchers from review items into blocks.python3 scripts/scan_copy.py --copy listing.txt
Add --hopa-verified only when step 6 has verified an older persons exemption for this property. Add --json when the findings need to go into a file or a ticket.
The scanner reports two severities:
Exit code 1 means at least one block. Exit code 0 with review items still means work to do. Exit code 2 means bad input.
The scanner deliberately does not flag wording HUD treats as acceptable: master bedroom, desirable neighborhood, walk-in closets, great view, walk to bus stop, kosher meals available, kids welcome, family room. A review that blocks those is overstating the law and teaching writers to ignore the review. references/phrase-table.md holds the full table, with fine items listed on purpose.
Read the whole set once as an ordinary reader who belongs to each protected class in turn, and check four things the phrase rules cannot see:
Write each finding with the exact passage quoted, the protected class, the source it rests on (statute, regulation, HUD guidance or platform policy), and the decision: cut, rewrite, or keep with the reason recorded.
Write the campaign settings into the JSON schema in the scanner header and run:
python3 scripts/scan_copy.py --targeting targeting.json
Then work references/targeting-checklist.md by hand. The load-bearing platform rules:
Check delivery after launch as well as settings before it. A skew visible in the delivery breakdown that nobody acts on becomes the advertiser's decision. Note what was checked, when, and what changed.
Do not let an exemption ride on a label. Each of these gets a yes or no with evidence in the record:
Every flagged phrase was doing a selling job. The rewrite keeps the job and drops the person:
| Flagged | What it was selling | Rewrite pattern | | --- | --- | --- | | perfect for young professionals | short commute, work space | name the commute time with its source, the desk space, the broadband fact | | ideal for a growing family | room to spread out | bedroom count, second living room, yard size, storage | | quiet professional building | low noise | insulation and construction facts, quiet hours that apply to everyone | | safe neighborhood | peace of mind | low-traffic street, lighting, the property's own locks and alarm | | walking distance to the church | walkable area | measured distances to named amenities, given neutrally | | great for empty nesters | single level ease | main floor bedroom and bathroom, step-free entry, low maintenance yard | | exclusive community | quality and scarcity | the real features: lot size, amenities, build standard, price facts | | top schools | school quality | assigned school and district by name, with the lookup source and date |
Rules for rewrites: use only facts you can source, keep the length and energy of the original line, and never soften an exclusion into a hint. A hint that survives the scanner and still tells a class of readers to stay away has failed the ordinary reader test, which is the test that counts.
Worked review 1: a rental listing. The draft in examples/listing-bad.txt is three lines long and fails hard:
The scanner reports 4 block and 10 review. Blocks: adults only, no children, no wheelchairs, Christian home. Review items include perfect for young professionals, empty nesters, quiet professional building, safe neighborhood, walking distance to St. Mary's Church, mature tenants preferred, family-friendly, top schools and no Section 8. Run in a jurisdiction that protects source of income, the same file reports 5 block and 9 review, because no Section 8 becomes a block. The fixed version in examples/listing-fixed.txt reports 0 block and 1 review: the surviving item is the no pets pairing check, cleared in the rewrite by stating that assistance animals are accommodated. The rewrite kept every selling point that was real: sun, size, the 2023 kitchen, parking, the cul-de-sac, the station, the park, and schools given as assigned names with a dated district lookup instead of a ranking.
Worked review 2: the same copy for a verified 55 or older community. With exemption paperwork verified and the scanner run with --hopa-verified, the adults only line downgrades from block to a consistency check and the file reports 3 block and 11 review. The other blocks stand: an older persons exemption covers familial status only, so no wheelchairs and Christian home are still blocks, and no children still has to be reworded to the exemption's actual basis, housing for older persons, rather than a bare exclusion. The lesson: an exemption is class specific and paperwork specific, never a general pass.
Worked review 3: a Meta campaign. The settings in examples/targeting-bad.json describe a campaign with no category declaration, ages 28 to 55, women only, two ZIP codes, a 5 mile radius, a lookalike audience, exclusions for public housing interests, and an audience note aimed at homeowners and parents in affluent areas. The scanner reports 8 block and 1 review. Every block is a settings change, not a copy change: declare the category, open the age band to 18 to 65 plus, include all genders, drop the ZIPs, widen the radius to 15 miles, drop the lookalike and the exclusions, and rewrite the audience note around geography and listing views. The corrected settings in examples/targeting-good.json scan clean.
A review is done when the record holds: the material reviewed, the local class list used, the scanner output for copy and targeting, each human finding with its passage and decision, the exemption evidence where one was claimed, the final rewritten copy, and the name of the person who approved shipping it. Keep the record with the listing file. If a complaint or a tester ever asks how this ad was reviewed, the record is the answer.
Anything the reviewer cannot settle (a claimed exemption with partial paperwork, a shared living preference, a client insisting on flagged wording, a delivery skew with no clear cause) goes to counsel as an open item. The ad does not ship with the open item inside it.
Return all of the following:
If the material is clean, say so in the same format with the checks named. Clean means the scanner ran, the human read happened, and the targeting was checked, not that nothing was looked at.
examples/: listing-bad.txt, listing-fixed.txt, targeting-bad.json and targeting-good.json, used to test the scanner.publisher key 2e43c913833850e6d80f939677e3de76e806d47785c0f1caaca90f9d18c98e1e
No ratings yet — be the first to rate it.