USCG Vessel Inspection & Deficiency Monitor
Pricing
$10.00 / 1,000 vessel inspection change delivereds
USCG Vessel Inspection & Deficiency Monitor
Watches your vessels in the official USCG PSIX registry and charges only for a real change: a new port state control exam or inspection, a new deficiency, a deficiency cleared, or a case status change. For ship owners, charterers, marine insurers, P&I clubs and maritime compliance teams.
Pricing
$10.00 / 1,000 vessel inspection change delivereds
Rating
0.0
(0)
Developer
Radu Furtuna
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
5 days ago
Last modified
Categories
Share
Watches the vessels you name in the official U.S. Coast Guard PSIX registry (Port State Information eXchange) and reports only what actually changed since your last run:
changeType | What happened at the Coast Guard |
|---|---|
new_activity | A new activity appeared on the vessel — a vessel inspection, a port state control exam, an incident investigation, a boarding or an operational control action. |
deficiency_added | A new deficiency was written against an existing activity. |
deficiency_resolved | A deficiency on that activity was cleared (IsResolved went to true). |
case_status_changed | The activity's case status changed (for example Open → Closed). |
activity_updated | The Coast Guard corrected another substantive field of the activity (date, type, PSC-exam flag). |
Nothing else is delivered and nothing else is charged. A run where nothing changed produces no paid events at all.
Who this is for
- Ship owners and technical managers — a standing watch on your own fleet's US port state control record, instead of re-checking PSIX by hand before every US call.
- Charterers and brokers doing pre-fixture vetting: a new PSC exam or an open deficiency on a candidate ship changes the decision.
- Marine insurers, P&I clubs and underwriters monitoring the insured fleet's USCG inspection record between renewals.
- Maritime compliance and QHSE teams tracking when a written deficiency is finally cleared.
How it works
monitorIdnames a durable history. The first run of a newmonitorIdis a silent baseline — it records the current state of every activity in each vessel's window, delivers nothing and charges nothing.- Every later run walks each vessel in three steps against PSIX — confirm the vessel, list its
activities inside the watch window, then pull the deficiencies of every activity in that window —
and compares the result against the durable per-activity index ().ActivityId -> content hash, case status, deficiency counts, change sequence
- Each genuine change is written to the dataset, then charged at most once — the right to deliver
and charge is granted by a single atomic claim keyed on
ActivityId+ change sequence + content hash (see Delivery guarantee below). A deficiency that is written, cleared, then written again with the same wording and cleared again produces four separate paid events, not two: the change sequence distinguishes repeats across the activity's history. - An optional HTTPS
webhookUrlreceives a digest of the delivered (paid) changes.
Run it on an Apify schedule; daily is a sensible cadence.
Finding your vesselId
vesselId is the internal PSIX vessel number, not the IMO number and not the call sign. PSIX 1837 is
MAERSK IDAHO, whose IMO is 9193264. Look the number up once at
cgmix.uscg.mil/PSIX by vessel name, call sign or IMO, then keep it in
your input. Every delivered row carries the vessel's name, IMO/official number and flag, so a wrong
number shows up on the first event rather than a year later. A vesselId PSIX does not know is reported
as watch_target_not_found and never produces a silent empty baseline.
Pricing
Pay per event: one event per delivered inspection change. No change, no charge. Charging happens only after the row has been written to both the durable dataset and the run's own output dataset.
Delivery guarantee: at-most-once (not exactly-once)
For any one computed change, the row is delivered to the dataset and the event is charged no more than
once. The right to do either is handed out by the only atomic primitive Apify offers —
RequestQueue.addRequest(uniqueKey) — in a separate, named request queue
(<storage prefix>-<monitorId>-claims) used purely as an append-only journal of granted rights: its
requests are never handled and never deleted. Apify's key-value store has no compare-and-swap,
conditional write or ETag, so it cannot be the source of that right; it only holds a diagnostic state
machine for reporting. The same gate also decides, atomically, which vessel and window a watchId is
permanently bound to.
The trade-off is deliberate: if a run crashes after taking the claim, that change can be lost (it is
closed as dataset_unknown / charge_unknown and never re-delivered) — but you are never charged twice
for it. Two boundaries of the guarantee, stated honestly:
- it holds for as long as the named claims queue exists. Anyone with account access can delete or recreate that queue through the Console/API, which starts the journal from scratch — an unavoidable limit of any durable storage, not a defect of the protocol;
- it applies from the build in which the claim gate shipped onward. Older builds must not keep running
against the same
monitorId.
Honest limits
- This is a registry-publication monitor, not a seaworthiness or compliance assessment. It reports what the U.S. Coast Guard publishes in PSIX and when that publication changes. It is not a determination of seaworthiness, not evidence of SOLAS / MARPOL / ISM compliance or non-compliance, not a class survey and not a legal opinion. Absence of a deficiency in PSIX is not proof that a vessel has none. Before any fixture, purchase, insurance or port decision, use the Coast Guard's own records and a qualified surveyor.
- The durable dataset is a delivery-attempt log, not a guaranteed mirror of the default dataset.
Each row is written to the durable dataset first, then mirrored to the run's default dataset before
billing proceeds for that row. If the durable write succeeds but the default-dataset mirror write
fails (e.g. transient Apify storage error), the item is marked
dataset_unknown, billing for it is permanently blocked (fail-closed — we never charge for a row we can't confirm was delivered), and the run is not retried into re-creating that exact row. The durable dataset can therefore end up with a small number of orphan rows that were never mirrored and never billed. The default dataset is the canonical log of rows successfully written to this run's output (see itsrun_summaryrow) — but a default-dataset row does not by itself prove the row was billed: the row is written beforeActor.charge()runs, so if charging then fails or comes backcharge_unknown, the row is present but not confirmably paid.run_summary.eventsBilledand Apify's own billing ledger are the source of truth for confirmed payment, not the presence of a row in either dataset. - Update cadence and completeness are the Coast Guard's, not ours. PSIX publishes on its own schedule; an exam held today may surface days later, and USCG activity only exists for vessels that actually call at US ports. Verified live on 13.09.2026: of 24 active vessels checked in one large fleet, only 3 had any PSIX activity at all since 2024. A quiet vessel produces quiet runs — and no charges.
- The watch window is a rolling
lookbackDays(default 365, max 3650) and is fixed perwatchId. Widening it later would pull in older activities that are not in the index yet and bill them as brand new, so awatchIdis permanently bound to both itsvesselIdand itslookbackDays; changing either fails the run withwatch_config_mismatchbefore any network request. Use a newwatchIdfor a different window (it starts with its own free baseline). - A window holding more than 20 activities is refused, not silently truncated (
target_too_broad). A busy US-calling ship logged 12 activities over nearly three years, so 365 days sits far inside the limit — but a truncated list would make activities look like they vanished and then, on the next run, like they were brand new and billable, so it is refused instead. - An activity that drops out of the rolling window is reported, never billed, and never deleted from
the index (
coverage.missingFromWindowCount). Keeping it frozen means that if the window ever shows it again it cannot be charged a second time as if it were new. - A drop in an activity's deficiency count is treated as a broken response, not as good news. The
Coast Guard does not delete deficiencies it has written, so "there are fewer now" means the service
returned an incomplete answer. The vessel is reported as
source_access_limitedfor that run — no delivery and no billing — and the index is left untouched so the next run recovers on its own. This is deliberate: silently reading it as a cleared deficiency would charge you for an improvement that never happened. - Only substantive fields drive billing. The billing hash covers the activity's start date, type, case status and sub-status, PSC-exam flag and administrative-check flag, plus the text and resolved flag of every deficiency. Re-assigning the activity to a different USCG zone port, or churn in PSIX's internal identifiers, is administrative noise and is deliberately not charged — even though the row shows the newest values whenever a real change is delivered. Deficiency ordering does not matter either: the set is compared order-independently, so a reshuffled response is not a paid event.
- Deficiencies have no stable ID in PSIX. The service exposes no per-deficiency identifier, so a deficiency is identified by its text and resolved flag. Two deficiencies whose wording is edited by the Coast Guard will read as one cleared and one added.
- Some PSIX responses are not valid XML and are repaired, not rejected. The service embeds inspector
free text that can contain control characters illegal in XML 1.0 (observed live in 2 of 83 activities).
Those characters — and only those — are deterministically replaced with
U+FFFDso one malformed deficiency cannot lock a vessel out of monitoring forever; the count is reported incoverage.sanitizedControlCharCount. - Anything else unexpected in a response is fail-closed. A missing result element, a
soap:Fault, a vessel ID or activity ID in the response that does not byte-for-byte match the one requested, a repeatedActivityId, a missing required field or a whitespace-only value all report the vessel assource_access_limitedfor that run — no baseline, no delta, no billing — rather than guessing. - At most 50 changes per vessel per run are delivered (
change_cap_reached). This protects your wallet from an anomalous bulk re-publication on the source side. The remaining changes are not lost — they are picked up by the following runs, inActivityIdorder. - Only one run per
monitorIdat a time. Concurrent runs are serialised by a durable lease; a run that loses the lease stops immediately, reportslease_lost, and never delivers or charges anything further.
Output
Dataset rows carry watchId, vesselId, vesselName, vesselIdentification (IMO or official number),
vesselFlag, vesselCallSign, vesselServiceType, vesselStatus, activityId, changeType,
activityType, startDtTm, processStatus/previousProcessStatus, processStatusDetail,
uscgZonePort, portStateControlRelatedExam, administrativeDeficiencyCheck, deficiencyCount/
previousDeficiencyCount, unresolvedDeficiencyCount/previousUnresolvedCount,
topDeficiencyDescription, the full deficiencies array (description, resolved flag, system,
sub-system, system component, action, action code, failure cause, resolution text and dates), plus
monitorId, runId, discoveredAt and eventId.
coverage (key-value store) records, for every run: each watch's vessel, window, status, reason,
activities and deficiencies in the window and changes detected, plus run-level counters —
recordsDelivered, recordsBilled, sourceAccessLimitedCount, vesselNotFoundCount,
targetTooBroadCount, changeCapReachedCount, missingFromWindowCount, sanitizedControlCharCount.
Source
U.S. Coast Guard PSIX SOAP service, https://cgmix.uscg.mil/xml/PSIXData.asmx. Public, free, no key or
registration required. Verified live on 13.09.2026.