MHVillage Manufactured Home Investor API
Pricing
from $5.00 / 1,000 results
MHVillage Manufactured Home Investor API
Search MHVillage.com manufactured and mobile home listings by state, city or ZIP, with built-in deal scoring that flags homes priced well below comparable listings in the same run.
Pricing
from $5.00 / 1,000 results
Rating
0.0
(0)
Developer
Tam Nguyen
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
2 days ago
Last modified
Categories
Share
๐๏ธ MHVillage Manufactured Home Investor API
Most scrapers hand you rows. This one hands you a shortlist: manufactured and mobile home listings from MHVillage.com โ the largest marketplace for manufactured housing in the US โ pre-scored against each other on price-per-square-foot, so the underpriced listings are flagged before you've opened a single one.
Search a whole state across multiple cities or ZIPs in one run, with automatic pagination, optional full-description/year/manufacturer enrichment per listing, and a built-in fallback that shows you where the inventory actually is when you search too broadly. Pull it straight into a spreadsheet, a CRM, a deal-sourcing pipeline, or your own underwriting model via the API.
Use cases:
- Deal sourcing โ scan a whole state for listings priced well below their comps
- Market research โ pull comparable sales/asks for a submarket before pricing a unit
- Inventory monitoring โ scheduled runs to catch new listings in target areas
- Portfolio tracking โ watch specific cities or ZIPs for competitor pricing moves
What data does it extract?
| Field | Description |
|---|---|
๐ state, city | The location this result came from |
๐ท๏ธ listingType | for-sale or for-rent |
๐ name, address | Listing title and full street address |
๐ฐ price | Listing price in USD, when it could be matched with certainty (see note below) |
๐๏ธ bedrooms, bathrooms, sqft | Home size |
๐ pricePerSqft, groupMedianPricePerSqft | This listing's $/sqft vs. the median for everything else pulled in the same run |
๐ฉ isLikelyDeal | true when priced at or below 85% of that median |
๐ description, year, make | Full listing description, model year, and manufacturer โ only populated with enrichWithDetailPage: true |
๐ผ๏ธ image | Listing photo URL |
๐ url, detailUrl | Direct links to the listing |
๐๏ธ resultType | listing, or city_directory when a bare-state search returns city-level counts instead (see Input) |
Features
- Multi-location in one run โ pass any number of
{ state, city }/{ state, zip }entries; each is searched and paginated independently - Automatic deal scoring โ every listing's $/sqft is benchmarked against the state-level median from the same run, no comps database to maintain
- State-level discovery โ search a bare state and get back a directory of every city with open inventory and how many listings each has, so you know where to aim before spending a run on it
- Optional detail-page enrichment โ opt into full description, year, and manufacturer per listing at the cost of one extra page load each
- Resilient extraction โ listings are read by data shape (structured data first, visible-text patterns as fallback), not hard-coded CSS selectors, so it degrades gracefully instead of breaking silently on minor site redesigns
- Self-diagnosing โ any run that comes back empty automatically saves the page HTML and a screenshot to the Key-Value Store so you can see exactly what the Actor saw
Input
{"locations": [{ "state": "TX", "city": "Austin" },{ "state": "FL", "zip": "33801" }],"listingType": "for-sale","maxListingsPerLocation": 100,"maxPagesPerLocation": 3,"enrichWithDetailPage": false,"computeDealScore": true}
| Field | Type | Default | Description |
|---|---|---|---|
locations | array | (required) | One entry per search: { "state", "city" }, { "state", "zip" }, { "state" } alone, or { "startUrl" } with a direct MHVillage search URL for exact control. A bare state with no city/zip returns a city directory instead of listings โ see Features. |
listingType | string | "for-sale" | "for-sale" or "for-rent" |
maxListingsPerLocation | integer | 100 | Stop collecting for a location once this many listings have been kept (1โ2000) |
maxPagesPerLocation | integer | 3 | Cap on result pages paged through per location, independent of maxListingsPerLocation (1โ50) |
enrichWithDetailPage | boolean | false | Visit each kept listing's own page for description, year, and make. Slower and uses more proxy bandwidth โ one extra page load per kept listing, not per listing found. |
computeDealScore | boolean | true | Compute pricePerSqft / groupMedianPricePerSqft / isLikelyDeal |
proxyConfiguration | object | US Residential | Must resolve to a US IP โ see Proxy |
Each entry in locations also accepts debugAlwaysCapture: true to force-save the page HTML and a screenshot to the Key-Value Store for that location regardless of whether it returns results, useful when you're debugging a specific search that looks wrong.
Running it
Console โ click Try for free, fill in the input form, hit Start.
API (amazinglabs-dev/mhvillage-investor-api):
curl "https://api.apify.com/v2/acts/amazinglabs-dev~mhvillage-investor-api/run-sync-get-dataset-items?token=<YOUR_API_TOKEN>" \-X POST \-H "Content-Type: application/json" \-d '{"locations": [{ "state": "TX", "city": "Austin" }],"listingType": "for-sale","maxListingsPerLocation": 100}'
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: '<YOUR_API_TOKEN>' });const run = await client.actor('amazinglabs-dev/mhvillage-investor-api').call({locations: [{ state: 'TX', city: 'Austin' }],listingType: 'for-sale',maxListingsPerLocation: 100,});const { items } = await client.dataset(run.defaultDatasetId).listItems();
from apify_client import ApifyClientclient = ApifyClient("<YOUR_API_TOKEN>")run = client.actor("amazinglabs-dev/mhvillage-investor-api").call(run_input={"locations": [{"state": "TX", "city": "Austin"}],"listingType": "for-sale","maxListingsPerLocation": 100,})items = client.dataset(run["defaultDatasetId"]).list_items().items
Runs can also be scheduled (Console โ Schedules) for recurring deal-sourcing, triggered via webhook on completion, or wired into Zapier/Make through Apify's standard integrations.
Output
Results land in a Dataset โ view as a table or JSON in the Console, or export to CSV, JSON, Excel, XML, or HTML. Pull it over the API (as above) straight into your own pipeline.
A real result searching Austin, TX:
{"resultType": "listing","state": "TX","city": "Austin","listingType": "for-sale","name": "15027 Moss Phlox Cir , Pflugerville, TX 78660","address": "15027 Moss Phlox Cir, Pflugerville, TX, 78660","price": 139995,"bedrooms": 4,"bathrooms": 2,"sqft": 2280,"pricePerSqft": 61.4,"groupMedianPricePerSqft": 77.1,"isLikelyDeal": true,"url": "https://www.mhvillage.com/homes/3564145"}
With enrichWithDetailPage: true, a real result also includes the full description, year, and manufacturer:
{"resultType": "listing","state": "TX","city": "Austin","year": 2021,"make": "Clayton","description": "Newly Remodeled 4BR/3Bath home with a garage for rent! Welcome home to this beautifully remodeled 4 bedroom, 2 bath home offering comfortable living space and excellent value...","detailUrl": "https://www.mhvillage.com/homes/3566169"}
A bare-state search returns a city directory instead, so you can see where the inventory actually is before committing a run to it:
{"resultType": "city_directory","state": "FL","city": "Alachua","forSaleCount": 1,"url": "https://www.mhvillage.com/homes/fl/alachua"}
On price: MHVillage's own listing markup doesn't include price directly โ this Actor reads it from the rendered page separately and only attaches it when it can match prices to listings with certainty (position-for-position, same count on both sides). When that isn't possible, every other field is still returned with price simply omitted from that item, rather than risking the wrong number on the wrong home.
Proxy
MHVillage blocks all non-US traffic at the network level, so this Actor requires a proxy that resolves to a US IP. It defaults to Apify's US Residential proxy group, which works out of the box on any plan with proxy access โ no configuration needed.
Troubleshooting
Extraction reads listings by data shape (structured data, then visible-text patterns) rather than fixed CSS selectors, so minor MHVillage redesigns shouldn't break it outright. If a run still comes back with zero results, check the Key-Value Store (Storage tab) for that run โ it automatically saves the full page HTML and a screenshot whenever it finds nothing unexpectedly. The most common cause is a proxy not actually resolving to a US IP; confirm apifyProxyCountry: "US" is still set.
Is this legal?
This Actor only reads listing pages that MHVillage serves to any visitor, logged in or not โ no account, paywall, CAPTCHA, or bot-check sits in front of this data. The US-only proxy requirement exists because MHVillage blocks foreign IP ranges at the network level, which is a geographic restriction, not an anti-bot measure to route around. That said, this isn't legal advice โ you're responsible for how you use the data you collect.
Pricing
Billed per the model shown on this Actor's Pricing tab in Apify Store. Cost scales with the number of locations, pages per location, and whether enrichWithDetailPage is enabled (it adds one browser page load per kept listing).
Roadmap
- Photos, community name โ not every field MHVillage shows visually is in its structured data yet
- Historical comps โ today's deal score compares listings within a single run; a persisted comps database across runs (compared against actual recent sales, not just today's other results) is the natural next step
- New-listing alerts โ scheduled runs that only report listings posted since the last run
- More marketplaces โ community-specific inventory and dealer-lot pages beyond the general search
Support
Found a bug or have a feature request? Open an issue on the Actor's source repository, or reach out via the Apify Console.