To inspect a POST body sent by a PhantomJS page, register page.onResourceRequested, filter requestData.method === 'POST', and read requestData.postData. That value is the body text; parsing it into fields or JSON is a separate step. If you need to send a POST yourself rather than observe one generated by page JavaScript, use page.open with a POST operation, serialized data, encoding, and matching headers.
Inspect an outgoing POST request
onResourceRequested runs when the page asks PhantomJS to fetch a resource. The callback receives request metadata in requestData and a request-control object as its second argument. The body is available as requestData.postData; it is not read from the second argument.
var page = require('webpage').create();
page.onResourceRequested = function (requestData, networkRequest) {
if (requestData.method === 'POST') {
console.log('POST to ' + requestData.url);
console.log('Raw body:');
console.log(requestData.postData);
}
};
page.open('https://example.com', function (status) {
console.log('Page load: ' + status);
phantom.exit();
});
The callback can fire for every resource, including images, stylesheets, analytics calls, XHR, and form submissions. Filtering by method prevents unrelated GET requests from filling your log. Add URL, headers, or other metadata checks when a page makes several POST requests.
Understand the callback arguments
requestData.methodidentifies the HTTP method.requestData.urlis the destination URL.requestData.headerscontains request headers supplied in the callback metadata.requestData.postDatacontains the outgoing body value identified by the PhantomJS community example.networkRequestis the control object used for operations such as aborting a request, changing its URL, or setting headers. Do not expect the body there.
Never log credentials, session cookies, authorization tokens, or personal data in production. Write selected fields to a protected diagnostic sink instead of printing every request.
Do these 3 things before closing this tab:
1Clear out junk files and repair common Windows errors2Fix the driver behind crashes, sound loss and screen glitches3Repair Windows errors before they cause bigger problems#1 Best Overall
Parse the body after reading it
Reading postData gives you a payload, not a parsed JavaScript object. First determine the request’s content type, then choose a parser. A body may be URL-encoded form data, JSON text, or another representation. The reviewed PhantomJS material does not establish that multipart bodies are always exposed as a simple, directly parseable string, so treat multipart uploads as a special case and verify the actual value in your target runtime.
JSON POST data
var page = require('webpage').create();
page.onResourceRequested = function (requestData) {
if (requestData.method !== 'POST') {
return;
}
var contentType = '';
for (var i = 0; i < requestData.headers.length; i++) {
if (requestData.headers[i].name.toLowerCase() === 'content-type') {
contentType = requestData.headers[i].value.toLowerCase();
break;
}
}
if (contentType.indexOf('application/json') !== -1) {
try {
var object = JSON.parse(requestData.postData);
console.log(JSON.stringify(object));
if (object.user) {
console.log('User: ' + object.user);
}
} catch (error) {
console.log('Invalid JSON body: ' + error.message);
}
}
};
page.open('https://example.com');
Do not call JSON.parse on every POST blindly. A form body such as user=alice&active=true is not JSON and will throw. JSON values also preserve types: a number remains a number and a Boolean remains a Boolean, whereas form parsers generally start with strings.
URL-encoded form data
For application/x-www-form-urlencoded, split on ampersands and decode each name/value pair. This small parser avoids depending on a package that may not be available in an older PhantomJS installation:
function parseFormBody(body) {
var result = {};
if (!body) {
return result;
}
var pairs = body.split('&');
for (var i = 0; i < pairs.length; i++) {
if (!pairs[i]) {
continue;
}
var parts = pairs[i].split('=');
var key = decodeURIComponent(parts.shift().replace(/+/g, ' '));
var value = decodeURIComponent(parts.join('=').replace(/+/g, ' '));
result[key] = value;
}
return result;
}
page.onResourceRequested = function (requestData) {
if (requestData.method === 'POST') {
var fields = parseFormBody(requestData.postData || '');
console.log(JSON.stringify(fields));
}
};
This example keeps duplicate keys by letting the last value win. If your server uses repeated names such as tag=a&tag=b, change the assignment to append values to an array. Also account for a missing value, an empty body, and malformed percent escapes if you are processing untrusted traffic.
The Tool Desk
Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Rank #2
Choosing the target request
Single-page applications often submit several POSTs. Match the endpoint before parsing:
page.onResourceRequested = function (requestData) {
if (requestData.method === 'POST' &&
requestData.url.indexOf('/api/orders') !== -1) {
console.log(requestData.postData);
}
};
For stricter matching, compare the complete URL or use a regular expression that cannot accidentally include a similarly named endpoint. If the request is created after a click, install the handler before opening the page and before triggering that click.
Observe requests versus send a controlled POST
These are different jobs. Use onResourceRequested when a loaded page generates the request and you want to observe its real body. Use page.open when your script already knows the endpoint and payload and must create the request itself.
Send URL-encoded data with page.open
var page = require('webpage').create();
page.open(
'https://example.com/login',
'post',
'user=alice&password=secret',
function (status) {
console.log('Page load: ' + status);
phantom.exit();
}
);
The shorthand sends the method and body as arguments. Encode values before concatenating them; otherwise ampersands, plus signs, or non-ASCII characters can change the meaning of the form.
Recommended Free Tools
Send JSON with explicit settings
var page = require('webpage').create();
var settings = {
operation: 'POST',
encoding: 'utf8',
headers: {
'Content-Type': 'application/json'
},
data: JSON.stringify({
some: 'data',
another: ['custom', 'data']
})
};
page.open('https://example.com/api', settings, function (status) {
console.log('Page load: ' + status);
phantom.exit();
});
The content type and serialization must agree. Sending JSON text with a form content type can make a server reject or misinterpret the body. Conversely, a form endpoint generally expects URL-encoded text rather than a JSON string.
What the page.open callback status means
The callback’s status reports whether PhantomJS considers the page load successful or failed. It is not the HTTP status code of the response. To inspect response status, headers, content type, and loading stages, attach page.onResourceReceived.
Inspect the response separately
page.onResourceReceived = function (response) {
if (response.url.indexOf('/api/orders') !== -1) {
console.log(response.status + ' ' + response.url);
console.log(response.stage);
console.log(response.contentType);
}
};
onResourceReceived is response-side. It is useful for status and lifecycle diagnostics, but it cannot replace onResourceRequested when the question is the outgoing POST body. Large resources may produce multiple response callbacks, one per chunk, so do not assume one callback contains a complete response.
Reliable debugging workflow
- Create the page and register
onResourceRequestedbefore callingopen. - Filter by method and, when possible, by the exact endpoint.
- Log the URL, content type, and body length first; log the body only in a safe development environment.
- Choose JSON parsing or form parsing based on the content type. Catch JSON errors.
- Use
onResourceReceivedif you also need HTTP status or response headers. - Exit only after the request and relevant response have completed. Calling
phantom.exit()too early can terminate the observation.
Common failures and fixes
postData is undefined or empty
Confirm that the request is actually a POST and that the handler was installed before navigation or the user action that triggers it. Some requests legitimately have no body. Also check that you are reading requestData.postData, not networkRequest.postData.
Rank #4
JSON.parse throws an exception
The body may be form-encoded, empty, truncated, or not JSON despite a misleading header. Print the content type and raw value in a controlled test, then parse only when the media type is JSON. Keep the try/catch so one malformed request does not stop the page script.
Form fields contain the wrong characters
URL-encoded data uses percent escapes and represents spaces as plus signs. Decode plus signs before calling decodeURIComponent, and ensure the sender and receiver agree on UTF-8. Do not split on every equals sign: values can legally contain =.
The page load says failure but the server received the POST
page.open‘s callback status is a page-load result, not an HTTP status. Check onResourceReceived for the response code and stage, and inspect network or TLS errors separately.
No request appears after a click
Install handlers before opening the page, wait for the page’s scripts to initialize, and trigger the click through PhantomJS after navigation. If the site uses a delayed XHR, keep the event loop alive long enough for it to be emitted.
Quick wins for a faster PC:
Scan for outdated or missing drivers - takes under a minuteDriver Scan →Clear out junk files and repair common Windows errorsFree Scan →Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Best Value
A large response appears several times
This is expected for chunked delivery: onResourceReceived may run for each chunk. Aggregate response data only if you need the complete body, and key your buffer by URL or another request identifier.
PhantomJS status and compatibility
PhantomJS is a legacy runtime. Its project repository says development is suspended until further notice and identifies 2.1 as the latest stable release; the changelog dates version 2.1.0 to 2016-01-23. Those facts describe project status, not compatibility with a particular current website, certificate chain, JavaScript feature, or TLS configuration. Test against the exact pages you need, and expect modern bot checks, browser APIs, or encryption settings to fail in an unmaintained engine.
Or skip the browser setup
If your goal is a clean screenshot or PDF rather than request instrumentation, ScreenshotNeo provides a website screenshot API and MCP server. A single request can capture a page without maintaining a PhantomJS runtime:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
See the ScreenshotNeo documentation for parameters. Before capture it accepts cookie or consent banners and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each cleanup step can be disabled. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and billing result. Its MCP server exposes take_screenshot, get_page_info, and capture_pdf to Claude, Cursor, and other MCP clients. The Free plan includes 1,000 screenshots per month without a card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account to try it.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
FAQ
Does onResourceReceived expose the POST body?
No. It is for response metadata and can be called in chunks. Read the outgoing body in onResourceRequested.
Can PhantomJS automatically convert every POST to an object?
No. postData is raw payload data. Your code must select and run an appropriate parser.
Can I change a request while inspecting it?
The second callback argument is the request-control object for operations such as aborting, changing the URL, and setting headers; body inspection remains on requestData.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

