Part 2: Building the Serverless Visitor Counter
2025-08-20
The visitor counter was my first dynamic feature on this site. It needed to save one number, update it when the resume loaded, and return the new value to the browser.
The request path
- The browser loads the static resume through CloudFront.
- Its JavaScript calls
GET /counton API Gateway. - Lambda increments an item in DynamoDB.
- The API returns the updated
visitsvalue as JSON.
The current endpoint increments on GET; it does not expose separate read and write operations. That was sufficient for the challenge, although a POST for increments and a read-only GET would be a clearer API contract.
Updating the count safely
A read-modify-write sequence can lose increments when two requests read the same starting value. The Lambda uses DynamoDB’s atomic ADD operation instead:
resp = table.update_item(
Key={"id": "site"},
UpdateExpression="ADD visits :inc",
ExpressionAttributeValues={":inc": 1},
ReturnValues="UPDATED_NEW",
)
This protects the increment itself from that race. It does not deduplicate retries or repeated page loads.
Why managed services
Lambda, API Gateway, and DynamoDB fit a small backend without requiring me to run a server. The tradeoff is having to understand permissions, request behavior, and service configuration across several components.
API Gateway’s CORS configuration allows the resume origin. CORS controls browser access to responses; it is not authentication and does not prevent direct API calls.
What the number means
The counter records successful increments, not unique visitors. Refreshes, repeat visits, automated requests, and direct calls can all increase it. It is a learning feature rather than a reliable recruiting or audience metric.
If the request fails, the resume displays n/a and the page remains usable. The counter should not block someone from reading my experience.

The Lambda implementation, backend tests, and API configuration show the current behavior.
Previous: hosting the portfolio · Next: making the portfolio repeatable