Use Commerce Integration Layer signals to detect extension errors and set up alerts in your Application Performance Monitoring (APM) tool.
Because the Commerce Integration Layer runs your extension code in a managed environment, you cannot monitor the performance of the extensions directly. Instead, monitor the
signals the environment emits: outbound calls, execution timeouts, and latency.
Use the signals described in this guide to detect extension errors and performance issues. With this information, optimize the performance of your extensions according to the guidance in
Operations and performance.
Shared responsibilities
While commercetools monitors platform reliability, you are responsible for monitoring your extension code, external dependencies, and your identity provider (IdP).
Your responsibilities
commercetools does not alert on failures originating inside your extensions. You must set up alerts for these issues in your APM tool.
Set up monitoring for the following conditions:
Signal sources
Signals come from two sources: Platform Insights and the Deployment Logs API or CLI. Some signals are available from both. Before setting up an alert, confirm which source you use. Platform Insights and the Deployment Logs API or CLI expose different fields and have different access methods.
Extension runtime logs
JSON logs from the
Deployment running your extension. They cover outbound HTTP calls and Managed API Extension deadlines, which are described in the sections below.
Query the logs using the
Deployment Logs endpoints or
commercetools connect deployment logs. The fields of each log line are in
details.
To alert on them in your APM tool, use
Platform Insights. Alternatively, poll the Deployment Logs API or CLI yourself and feed the result into your own alerting.
Only alert on the log messages and fields listed on this page. Unlisted log lines can change without notice.
Outbound HTTP calls
Every fetch call writes a log with message: "EXTENSION HTTP REQUEST" and event: "extension.http_request". Query strings and headers are not logged.
level | Meaning |
|---|
info | A response was received. Check http_response_status_code for the result. |
warn | The request was blocked before sending. See extension_fetch_refused_reason. |
error | The request failed without a response, for example because of a network failure or a canceled request. See error_type. |
Fields
| Field | Description |
|---|
event | extension.http_request |
http_request_method | HTTP method |
url_scheme | https or http |
server_address | Target host (use to group alerts by dependency) |
server_port | Target port (if non-default) |
url_path | Target path |
http_response_status_code | HTTP status code |
http_response_body_size | Response size in bytes, from Content-Length. For a compressed response, this is the compressed size. |
http_response_body_encoding | Response Content-Encoding, or identity if none |
http_client_request_duration | Request duration in seconds |
http_client_queue_ms, http_client_connect_ms, http_client_dns_ms, http_client_tcp_ms, http_client_tls_ms, http_client_ttfb_ms | Time in milliseconds spent in each phase of the call. A field is omitted if the phase did not occur, for example no connect time on a reused connection. |
extension_fetch_allowed | true if sent, false if blocked |
extension_fetch_refused_reason | Reason the call was blocked |
extension_fetch_block_reason | Internal target type when blocked by blocked_target |
error_type | Error code for failed calls, for example ECONNREFUSED |
Response receivedjson
{
"level": "info",
"message": "EXTENSION HTTP REQUEST",
"event": "extension.http_request",
"http_request_method": "GET",
"url_scheme": "https",
"server_address": "api.us-central1.gcp.commercetools.com",
"url_path": "/my-project/orders/order-number=12345",
"http_response_status_code": 200,
"http_response_body_encoding": "gzip",
"http_client_request_duration": 0.42,
"http_client_queue_ms": 1,
"http_client_ttfb_ms": 410,
"extension_fetch_allowed": true,
"correlation_id": "6c1f0e3a-8d2b-4f57-9a41-2b7e5d0c9f13",
"extension_source_revision": "6f8e284fd23b",
"timestamp": "2026-10-02T01:51:15.778Z"
}
Blocked and failed request examples
The request was blocked before sending (warn):
Blocked requestjson
{
"level": "warn",
"message": "EXTENSION HTTP REQUEST",
"event": "extension.http_request",
"http_request_method": "POST",
"url_scheme": "https",
"server_address": "api.example.com",
"url_path": "/v1/orders",
"extension_fetch_allowed": false,
"extension_fetch_refused_reason": "host_not_allowlisted",
"correlation_id": "6c1f0e3a-8d2b-4f57-9a41-2b7e5d0c9f13",
"timestamp": "2026-10-02T01:51:15.778Z"
}
The request failed without a response (error):
Failed requestjson
{
"level": "error",
"message": "EXTENSION HTTP REQUEST",
"event": "extension.http_request",
"http_request_method": "GET",
"url_scheme": "https",
"server_address": "api.example.com",
"url_path": "/v1/orders",
"http_client_request_duration": 0.03,
"extension_fetch_allowed": true,
"error_type": "ECONNREFUSED",
"correlation_id": "6c1f0e3a-8d2b-4f57-9a41-2b7e5d0c9f13",
"timestamp": "2026-10-02T01:51:15.778Z"
}
Refused request reasons
The extension_fetch_refused_reason field shows why a request was blocked.
| Cause | Action |
|---|
host_not_allowlisted | Host is not on the allowlist. | Add the host to the outbound HTTP domain allowlist. |
host_denied | Host is on your allowlist but blocked by commercetools. | Call a different host. |
blocked_target | Target is an internal IP or metadata address. Allowlisting the host has no effect. | Use a public endpoint. |
bad_protocol | Protocol is not http or https. | Use https. |
invalid_url | Malformed URL. | Fix the URL. |
instance_retired | Code executed after the request finished. | Ensure async work finishes before returning. |
Recommended HTTP alerts
These alerts use extension runtime logs, available in Platform Insights and through the Deployment Logs API or CLI (see
Extension runtime logs). Create alerts in your APM tool or poll the Deployment Logs API to drive your own alerting.
| Trigger | Typical cause |
|---|
level is warn and extension_fetch_refused_reason is host_not_allowlisted | A new release is calling an unapproved host. |
High rate of level error for a single server_address | Target host is unreachable. |
High rate of http_response_status_code 500 or above for a single server_address | Target host is failing. |
More than 5% of calls to a server_address exceed your latency budget | Target host is slow. |
Managed API Extension deadlines
When a Managed API Extension exceeds its
deadline, the write fails. The following log is available for this case.
Fields
| Field | Value |
|---|
level | error |
message | api-extension handler exceeded its deadline |
event | api_extension.timeout |
handlerKey | Key of the timed-out handler |
deadlineMs | Deadline that applied to the handler, in milliseconds. |
Handler deadline exceededjson
{
"level": "error",
"message": "api-extension handler exceeded its deadline",
"event": "api_extension.timeout",
"handlerKey": "validate-cart",
"deadlineMs": 1750,
"correlation_id": "6c1f0e3a-8d2b-4f57-9a41-2b7e5d0c9f13",
"timestamp": "2026-10-02T01:51:15.778Z"
}
Recommended deadline alerts
The first trigger uses an extension runtime log, available in Platform Insights and through the Deployment Logs API or CLI. The other two are Platform Insights signals forwarded to your APM tool.
| Trigger | Typical cause |
|---|
Any log with event api_extension.timeout (Platform Insights, Deployment Logs API, or CLI) | Handler is timing out. Optimize code or increase timeoutInMs. |
Platform Insights: extension_duration in the extension logs approaches the handler's timeoutInMs | Handler latency is close to failing writes. Group by extension_key, which contains the handler's key, to find the handler. |
Platform Insights: ct_extension_time_sec rises | Overall extension latency is increasing. The metric isn't broken down by extension, so use the extension logs to find which one. |
Identity provider errors
Every call to your configured
identity provider (code exchange at sign-in, token refresh, or revocation at sign-out) writes one log line with
upstream: "idp" and the IdP's HTTP response status. Platform Insights forwards this line to your APM tool. It isn't available through the Deployment Logs API or CLI.
Use the upstream field to distinguish identity provider calls ("idp") from commercetools calls ("commercetools").
An incorrect client secret is typically rejected by the IdP with a 4xx status and logged at info. To find rejected requests, alert on http_status_code rather than on level.
Identity provider logs
The log lines are identified by upstream: "idp" and ct_service_name: "integration-layer". They don't include the request query, headers, or body, because they carry the client secret and tokens.
The level depends on whether the identity provider responded, not on whether it accepted the request:
| IdP outcome | level |
|---|
| Response with a status below 500, including 4xx | info |
| Response with a status of 500 or above | warning |
| No response (timeout, DNS failure, and so on) | err |
In addition to ctp_project_key, duration, environment, level, message, severity, and timestamp, each log entry contains the following fields:
| Field | Description |
|---|
upstream | idp |
http_method | HTTP method. |
http_host | Identity provider host. |
http_path | Identity provider endpoint path. |
http_status_code | HTTP status code of the identity provider response. Absent if the request failed without a response. |
http_status | Same value as http_status_code, kept for compatibility. |
http_response_time_ms | Request duration in milliseconds. |
http_received_bytes | Size of the response, from its Content-Length header. Absent if the response has none. |
http_response_content_type | Content-Type of the response. |
http_content_encoding | Content-Encoding of the response, or identity if none. |
The message contains the method, path, status, and duration. If the request fails without a response, the message is idp POST /oauth2/token failed: {reason} and the line has no http_status_code.
Example of an identity provider log entryjson
{
"ct_service_name": "integration-layer",
"ctp_project_key": "my-project",
"duration": 0.212,
"environment": "prod",
"http_content_encoding": "identity",
"http_host": "idp.example.com",
"http_method": "POST",
"http_path": "/oauth2/token",
"http_received_bytes": 87,
"http_response_content_type": "application/json",
"http_response_time_ms": 212,
"http_status": 503,
"http_status_code": 503,
"level": "warning",
"message": "idp POST /oauth2/token 503 212ms",
"severity": "warning",
"timestamp": "2026-10-02T01:51:15.778Z",
"upstream": "idp"
}
Recommended identity provider alerts
| Alert trigger | Common cause |
|---|
Any log with upstream: "idp" and http_status_code of 400 or above, or with level err (no response) | Sign-in, token refresh, or sign-out was rejected or failed, or the IdP didn't respond. |
High rate of upstream: "idp" calls with http_status_code 400 or above, for a single Project | Invalid IdP credentials, incorrect endpoint configuration, rate limiting, or an IdP outage. |
More than 5% of upstream: "idp" calls exceed your latency budget (duration) | The IdP is slow. |
Control plane
Control plane tasks (enrolling projects, publishing bundles, configuration) return status directly, so log alerts are not required:
- CI/CD pipeline: run
commercetools integration-layer extension push without --no-wait. The command waits for the extension to load the bundle, for up to 180 seconds by default (set it with --wait-timeout). If the bundle fails to load, the command prints the failure reason and exits with a non-zero code. The project keeps serving the previous working revision. If the wait times out, the command doesn't fail, so check its output for the result.
- Status checks: run
commercetools integration-layer extension status at any time to see the newest stored revision (version, size, upload time, filename, uploader, and sourceRevision when recorded). It doesn't report lifecycle state, a failure reason, or which revision is actually served — for the outcome of a specific push, use its own --wait output; to check at any later time, use the Merchant Center extension panel. If nothing has ever been pushed, the command reports that no extension code is stored.