Can I return a JSON blocking response instead of HTML for API clients?
Short answer
Yes. If only API requests should get JSON, a Content Pages profile of the application/json type and, optionally, a separate status code (e.g. 403) are added to the Conditional Blocking Pages list in the Blocking Page window with a condition that separates the API requests (e.g. path starts with /api/); the other requests continue to get the HTML page. If it is enough that all the blocking responses be JSON, the JSON default blocking page template under Ready-made Templates sets the source to Manual content and the type to application/json, puts {"attackInfo": %WAF_INFO} into the body and removes the existing conditional pages. %WAF_INFO writes the attack details (by default the signature ID, the attack area, the score and the monitoring status) to the response; if the details should not be shown to the client, only a request ID such as %UID is left in the body. The setting is saved with Edit.
Problem: API Clients Get an HTML Body When Blocked
API clients and mobile applications cannot parse the HTML blocking page; their error handlers need a structured (JSON) body and an expected status code.
Solution: Three Methods
| Your situation | Suitable method |
|---|---|
| Only API requests should get JSON, the others HTML | Method 1: Conditional JSON page |
| All blocking responses should be JSON | Method 2: JSON template |
| I will make the default blocking response JSON with a script or the command line (conditional pages stay) | Method 3: WEB-CLI |
Method 1: Conditional JSON Page Recommended
- How it works A JSON page profile and a status code are bound to the condition that separates the API requests; the requests that do not match the condition get the default page.
- Where it is opened Content Pages · Conditions · Blocking Page card → pencil icon → Conditional Blocking Pages
- Requirement A Content Pages profile of the
application/jsontype and a request condition that separates the API requests (adding on the Content Pages and Conditions screens requires modify permission in the Load Balancer area) - Limit At most five conditional pages
Step-by-Step Configuration
On the Load Balancer → Profiles → Content Pages screen, Add is clicked (how to add).
Content Page Name is given, application/json is written in the Content Type field and the body is entered in the Content field:
{"error":"blocked","requestId":"%UID"}Add is clicked; the page is added to the profile list.
On the Load Balancer → Conditions screen, Add is clicked (how to add).
Criteria = Path is selected; Start is selected in the unlabeled matching method list and /api/ is written in the Query field. If the APIs are not separated by path, an HTTP Header condition (e.g. the Accept header Includes application/json) is used.
Add is clicked; the condition is added to the list.
In the Left Monitor Panel → WAF-Protected vServices → vService → WAF Management tab, the pencil icon at the top right of the Blocking page card in the Inspection & Blocking section is clicked.
Under Conditional Blocking Pages, Add Conditional Page is clicked; a new entry titled CONDITIONAL PAGE #n opens.
In the Condition field of the entry (it shows Select conditions while empty), the condition from step 6 is selected.
In the Page Profile field, the JSON page from step 3 is selected.
In the Status Code field, 403 is selected; if Use Default Status Code is left, the entry uses the Blocking Status Code value.
Edit is clicked; the change is applied without a separate deployment step. In a cluster setup, it is also sent to the peer device with the default auto-sync; if Manual Sync Mode is on, it is sent to the peer device manually.
Verification
The conditional page row on the Blocking page card on the WAF Management tab is examined.
<condition> → the <JSON page> page is shown (403)A request that triggers a signature on the API path is sent to the host group in Blocking mode.
Command: curl -i "https://www.example.com/api/items?q=%3Cscript%3Ealert(1)%3C/script%3E"
HTTP 403 · content-type: application/json; charset=utf-8 · {"error":"blocked","requestId":"…"}/api/, the default HTML page is returned.Method 2: JSON Template
- How it works The default blocking response becomes JSON; since the template removes the existing conditional pages, all the blocks get this body.
- Where it is openedBlocking Page card → pencil icon → Ready-made Templates → JSON Default Blocking Page
- Requirement WAF-enabled HTTP vService
- Scope The existing conditional pages are removed
Step-by-Step Configuration
Left Monitor Panel → WAF-Protected vServices → vService → WAF Management → the pencil icon at the top right of the Blocking Page card is clicked.
The JSON Default Blocking Page template under Ready-made Templates is clicked.
The Apply "JSON default blocking page"? confirmation is accepted. If the form has conditional pages, This replaces the current blocking page settings, including the N conditional page(s) below. is written below the confirmation; with the confirmation, these entries are removed from the list. Blocking Page Source becomes Manual Content, Blocking Page Content Type becomes application/json, and {"attackInfo": %WAF_INFO} comes into the Blocking Page field.
If the attack details should not be shown to the client, the body in the Blocking Page field is changed to {"error":"blocked","requestId":"%UID"} (Which Smart Variables can I use on the blocking page (%UID, %SRCIP, %WAFSCORE, %WAFINFO …); is it safe to show attack details?).
403 is selected from the Blocking Status Code list; the template does not change the code.
Edit is clicked; the change is applied without a separate deployment step. In a cluster setup, it is also sent to the peer device with the default auto-sync; if Manual Sync Mode is on, it is sent to the peer device manually.
Verification
The sentence of the Blocking page card on the WAF Management tab is examined.
A blocked client gets the inline content (application/json) with status 403Method 3: WEB-CLI
- How it works The source, the content type, the body and the code are written with WEB-CLI; the default response becomes JSON as in Method 2, but since the command changes only the written fields, the existing conditional pages remain.
- Where it is opened WEB-CLI →
waf options update - Requirement WEB-CLI access
- Scope The default blocking response; when a conditional JSON page is added with a command, the WEB-CLI steps on the Can I show a blocking page based on the visitor's language? page are followed
Step-by-Step Configuration
--blockingContentSource null sets the source to Manual Content; if the source stays Content Profile, the written body is not used. The command gives no output:
waf options update poolId <vService> --syncWithDefaultFwRules false --blockingContentSource null --blockingContentType application/json --blockingContent '{"error":"blocked","requestId":"%UID"}' --blockingStatusCode 403Verification
The WAF settings of the vService are displayed.
Command: waf options show poolId <vService>
blockingContentType application/json · blockingStatusCode 403Common Mistakes
- Returning
%WAF_INFOon an external API. The response shows the client the ID of the signature that caught the request, the attack area, the score and, depending on the setting, the attack pattern; for external clients, the request ID (%UID) is enough (Which Smart Variables can I use on the blocking page (%UID, %SRCIP, %WAFSCORE, %WAFINFO …); is it safe to show attack details?). - Leaving 418 with a JSON body. 418 is not a standard error code; the error handlers of API clients mostly expect 403 or 400.
- Relying only on the Accept header as the condition. Clients that do not send the Accept header do not match the condition and get the HTML page; if the APIs can be separated by path, the Path condition is preferred.
- Applying the JSON template while there are conditional pages. The template removes all the existing conditional pages; if the entries set up with Method 1 are to be kept, the template is not used, and Blocking Page Source and the page fields are changed manually (What are the ready-made blocking page templates (Turkish, English, JSON)?).
- Writing the body with a command and not changing the source. While the source is Content Profile, the written body is not used; the card continues to say A blocked client gets the … page.
How it is done in the documentation
