Tuning a Web ACL means answering "what did this rule actually match?" repeatedly, and AWS gives two different tools for that depending on whether you need a quick look or a durable trail. GetSampledRequests needs no setup and answers "what happened recently." PutLoggingConfiguration sets up a real pipeline and answers "what happened, ever, queryable later."
This page covers both, and when each is the right call.
GetSampledRequests is the fastest way to see what a rule is doing right now, with zero infrastructure. It returns up to 500 matched requests from the last 3 hours for one rule.
// --- TypeScript (AWS SDK v3) ---import { WAFV2Client, GetSampledRequestsCommand } from "@aws-sdk/client-wafv2";const wafv2 = new WAFV2Client({ region: "us-east-1" });const now = new Date();const threeHoursAgo = new Date(now.getTime() - 3 * 60 * 60 * 1000);const resp = await wafv2.send(new GetSampledRequestsCommand({ WebAclArn: "arn:aws:wafv2:us-east-1:111111111111:regional/webacl/app-web-acl/abc123", RuleMetricName: "blockBadHeader", Scope: "REGIONAL", TimeWindow: { StartTime: threeHoursAgo, EndTime: now }, MaxItems: 100,}));for (const item of resp.SampledRequests ?? []) { console.log(item.Action, item.Request?.ClientIP, item.Request?.URI);}
RuleMetricName must match the VisibilityConfig.MetricName you gave that specific rule when creating it - the sample is per-rule, not per-ACL. Three hours is the maximum lookback; there is no way to query further back through this API.
The Firehose delivery stream name must start with aws-waf-logs- - WAF enforces this naming convention on the destination. RedactedFields removes the field's value from the log entry entirely (replaced with a redaction marker) rather than just masking part of it. The LoggingFilter here keeps only BLOCK-action entries, which cuts volume dramatically on a busy ACL where most traffic is allowed.
PutLoggingConfiguration accepts a Kinesis Data Firehose ARN, a CloudWatch Logs log group ARN, or an S3 bucket ARN in LogDestinationConfigs - the same call, just a different ARN shape. Firehose is the most common choice because it can fan out to S3 (for querying with Athena) and to an analytics tool simultaneously. CloudWatch Logs is simplest for teams already living in CloudWatch. Direct-to-S3 logging skips Firehose entirely for the lowest-latency, simplest pipeline when you do not need real-time forwarding elsewhere.
GetSampledRequests works whether or not PutLoggingConfiguration is set up - it reads from WAF's own internal sampling, not from your log destination. Many teams use sampling exclusively during initial rule development (fast iteration, no infrastructure) and only turn on full logging once a rule is stable enough to be worth long-term retention and querying.
Without a LoggingFilter, every evaluated request that matches at least one rule gets logged - including ALLOW matches from managed rule groups running in normal operation, which on busy traffic can be the overwhelming majority of log volume. A filter keeping only BLOCK and COUNT actions focuses the log on what actually needs review, while cutting storage and Firehose/CloudWatch costs proportionally.
RedactedFields operates at the point of log generation, not as an after-the-fact scrub. Once a field is configured for redaction, its value never appears in any destination - there is no way to retroactively "unredact" older log entries, so get the redaction list right before sensitive fields ever ship to a destination you do not fully control.
Firehose stream name without the required prefix.PutLoggingConfiguration rejects a Firehose ARN whose delivery stream name does not start with aws-waf-logs-.
Expecting GetSampledRequests to cover more than 3 hours. It cannot; anything older needs a logging destination set up in advance.
Logging everything on a high-traffic ACL. Without a LoggingFilter, logging every ALLOW from a busy managed rule group can generate enormous log volume and cost; filter to BLOCK/COUNT unless you specifically need full traffic logs.
Forgetting to redact sensitive headers. Authorization headers, session cookies, and API keys land in plaintext logs unless explicitly listed in RedactedFields.
Assuming one logging configuration covers multiple Web ACLs.PutLoggingConfiguration is set per Web ACL's ResourceArn; each ACL needs its own call.
Not checking CloudWatch Logs resource policy. A CloudWatch Logs destination needs a resource policy granting WAF permission to write to it, or PutLoggingConfiguration fails silently on delivery even though the API call itself succeeds.
GetSampledRequests only, no persistent logging, suits early rule tuning and low-traffic applications where recent-traffic visibility is enough.
Direct-to-S3 logging skips Firehose when you only need raw log files for periodic batch analysis (Athena, QuickSight) and do not need a real-time stream elsewhere.
CloudWatch Logs is the simplest destination to wire up for teams already using CloudWatch dashboards and alarms, at the cost of CloudWatch's own ingestion and storage pricing.
Kinesis Data Firehose to multiple destinations (S3 plus an analytics or SIEM integration) is the most flexible option and the one most production security teams land on.
What is the maximum lookback for GetSampledRequests?
Three hours. For anything older, you need a logging destination configured in advance via PutLoggingConfiguration.
What destination types does PutLoggingConfiguration support?
A Kinesis Data Firehose delivery stream, a CloudWatch Logs log group, or an S3 bucket, each passed as an ARN in LogDestinationConfigs.
Why does my Firehose destination get rejected?
The delivery stream name must start with aws-waf-logs-; WAF enforces this naming convention and rejects any other name.
How do I keep sensitive headers out of my logs?
List them in RedactedFields when calling PutLoggingConfiguration. Redaction happens at log generation, so it must be configured before the sensitive data would otherwise be logged.
Can I log only blocked requests?
Yes, with a LoggingFilter whose filters keep only entries matching a BLOCK (or COUNT) ActionCondition, reducing volume on high-traffic ACLs.
Does GetSampledRequests require any logging setup?
No. It reads from WAF's internal sampling directly and works even with no PutLoggingConfiguration in place.