Self-Storage Rate Change Monitor | Web Rates & Promos avatar

Self-Storage Rate Change Monitor | Web Rates & Promos

Under maintenance

Pricing

$25.00 / 1,000 unit rate extracteds

Go to Apify Store
Self-Storage Rate Change Monitor | Web Rates & Promos

Self-Storage Rate Change Monitor | Web Rates & Promos

Under maintenance

Monitor supplied public self-storage facility pages for qualified changes to monthly web rates, promotions, and availability.

Pricing

$25.00 / 1,000 unit rate extracteds

Rating

0.0

(0)

Developer

Blake Panter

Blake Panter

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

15 days ago

Last modified

Share

Track competitor self-storage pricing on facility pages you already know. Each paid result is an initial qualified monthly-rate observation or a later rate, promotion, or availability change—not every price found on the page.

Output includes previous/current values, source evidence, change type, and a stable deduplication key.

This Actor monitors only supplied public self-storage facility pages. It does not discover facilities, render JavaScript-only booking portals, or guarantee support for every operator's markup.

What qualifies as output

A unit card must contain both a recognizable size (for example, 5x10) and a dollar amount explicitly labelled as a web, online, monthly, or per-month rate. Move-in prices, savings amounts, insurance prices, and other unlabelled dollar values are not treated as monthly rates. Output includes rateEvidence and qualification so the parser decision is auditable.

Same-size units remain distinct only when stable page evidence—a unit identifier, climate/drive-up features, or unit type—distinguishes them. Exact duplicate markup collapses to one observation. If multiple cards have the same stable identity dimensions but conflicting rates or availability, all of those ambiguous cards are rejected; the Actor does not use DOM order or a current price to invent identities.

Input

{
"startUrls": [{ "url": "https://operator.example/public-facility-page" }],
"maxPages": 25,
"maxItems": 100,
"requestTimeoutSecs": 30,
"maxHtmlBytes": 500000,
"outboxCapacity": 1000,
"snapshotCapacity": 10000
}
  • maxPages limits fetched URLs; maxItems independently limits paid events delivered in a run.
  • maxHtmlBytes is a strict per-page byte bound. Oversized or incomplete HTML is rejected rather than parsed after truncation.
  • Only public HTTP(S) URLs on standard ports are accepted. Initial URLs and every redirect are DNS-checked; private, loopback, link-local, reserved, metadata, credential-bearing, and non-HTTP(S) destinations are rejected.
  • Pages must return HTML. Individual fetch failures are skipped.

Stateful monitoring and delivery

State is stored in the named key-value store self-storage-price-monitor-state.

  1. A qualified unit first emits an initial event.
  2. An unchanged repeat emits nothing.
  3. A changed monthly rate, availability value, or promotion emits a corresponding change event.
  4. Pending events are drained before newer observations are staged.

Delivery is at least once. An event is written to a bounded persistent outbox before PPE output and acknowledged only after Actor.pushData succeeds. A crash between output acceptance and acknowledgement can duplicate an event, so consumers should deduplicate using the stable dedupeKey. Each newly staged occurrence receives a durable monotonic occurrenceSequence: retries retain the same sequence and key, while later recurring transitions such as $10 → $20 → $10 → $20 receive distinct keys. Legacy state is migrated without rewriting pending retry keys. Full state capacities apply backpressure; the Actor does not silently evict unpaid work or tracked history. Avoid overlapping runs against the same state store.

Output contract

The dataset and Actor output schemas are wired in .actor/actor.json. An illustrative event shape is:

{
"changeType": "rate_changed",
"changedFields": ["webRateAmount"],
"facilityName": "Operator name from page",
"unitId": "A-101",
"unitSize": "5x10",
"climateControlled": true,
"driveUp": false,
"webRate": "$89.00",
"webRateAmount": 89,
"previousWebRateAmount": 79,
"currency": "USD",
"available": true,
"qualification": "qualified-monthly-rate",
"rateEvidence": "Web rate $89.00 / month",
"sourceUrl": "https://operator.example/public-facility-page",
"detectedAt": "2026-08-26T12:00:00.000Z",
"identityKey": "...",
"occurrenceSequence": 42,
"dedupeKey": "..."
}

This is an illustrative contract example, not evidence from a live operator run.

Charging

The PPE event name is rate-change. Only records that pass the monthly-rate qualification gate reach Actor.pushData. maxItems is checked before staging newer payable work, and eventChargeLimitReached stops delivery immediately after the accepted event is acknowledged.

Supported and unsupported pages

The lightweight HTML parser recognizes common server-rendered unit cards (article, list/table rows, and common unit/rate classes). JavaScript-only inventory, bot challenges, login pages, booking/checkout flows, and operator-specific API calls are outside the current scope. Verify events against sourceUrl before making pricing decisions.

Local verification

The build uses exact direct dependency versions, a committed package-lock.json, npm ci, and a digest-pinned Node.js 24 image with npm 12.0.2. TypeScript is executed with tsx; tests use Vitest and linting uses Oxlint.

npm ci
npm run lint
npm test
npm run typecheck
npx --yes apify-cli validate-schema

Schema validation intentionally uses the Apify CLI's supported no-argument project command, which validates the input, dataset, and output schemas wired in .actor/actor.json. Passing dataset/output schema paths would incorrectly validate them as input schemas.

Tests use multiple local operator-style fixtures; no claim of current live-site compatibility is made from those fixtures.