Back to Blog
Lesson 15 of the Redis: Redis Essentials & Data Types course
DatabasesAugust 2, 20264 min read

Tracking Unique API Visitors with Redis Sets

Learn to track unique visitors to your API using Redis Sets. Master SADD, SCARD, and DEL commands to build efficient, real-time analytics for your application.

RedisAnalyticsSetsAPIBackendDatabases
Silhouettes of tourists observing the Dubai skyline from an indoor observation deck.

Previously in this course, we explored Set Operations: Intersection and Union in Redis, where we learned how to compare groups of data. Now, we’ll apply those concepts to a practical challenge: tracking unique API visitors.

In web development, "unique visitors" refers to the number of distinct users—typically identified by IP address, session ID, or user ID—that interact with your service over a specific period. Storing this in a traditional relational database often requires heavy SELECT DISTINCT queries that grow slower as your traffic scales. Redis Sets provide a high-performance alternative because they are designed by definition to hold only unique members.

Tracking Unique Visitors with Redis Sets

A Redis Set is an unordered collection of strings. The core property of a Set is that it automatically handles deduplication; if you try to add the same member twice, Redis simply ignores the second attempt. This makes it the perfect data structure for counting unique entities.

When we track visitors, we typically use three primary commands:

  1. SADD: Adds a new visitor ID to the set.
  2. SCARD: Returns the cardinality (the count) of the set.
  3. DEL: Clears the set once the reporting period (e.g., a 24-hour window) ends.

Worked Example: Visitor Analytics Service

Let’s integrate this into our project. We will create a simple service that tracks unique visitor IDs for a specific API endpoint.

JAVASCRIPT
const redis = require(CE9178">'redis');
const client = redis.createClient();

async function trackVisitor(endpoint, visitorId) {
  // We use a namespaced key: visitors:endpoint_name
  const key = CE9178">`visitors:${endpoint}`;
  
  // SADD returns 1 if the element was added, 0 if it was already present
  await client.sAdd(key, visitorId);
}

async function getUniqueVisitorCount(endpoint) {
  const key = CE9178">`visitors:${endpoint}`;
  
  // SCARD returns the total number of unique elements in the set
  const count = await client.sCard(key);
  return count;
}

async function resetDailyVisitors(endpoint) {
  const key = CE9178">`visitors:${endpoint}`;
  await client.del(key);
}

In this implementation, every time a request hits your API, you call trackVisitor. Because Redis keeps this data in memory, the overhead of checking for uniqueness is negligible, even at high traffic volumes. Unlike Standardizing Response Envelopes: Clean API Design Patterns, where we focus on the structure of data outgoing to the client, here we focus on the efficiency of data ingestion internal to our backend.

Hands-on Exercise

  1. Launch your redis-cli.
  2. Simulate three visits to a home page from two users (e.g., user "Alice" visits twice, "Bob" visits once).
    • SADD visitors:home "alice"
    • SADD visitors:home "bob"
    • SADD visitors:home "alice"
  3. Run SCARD visitors:home. You should see 2.
  4. Remove the tracking data using DEL visitors:home.

Common Pitfalls

  • Memory Growth: Since Sets store every unique ID, if your visitor count grows into the millions, the memory usage will climb. If you only need an approximate count for massive scale, consider looking into Redis HyperLogLogs in the future, which trade a tiny amount of accuracy for massive memory savings.
  • Forgetting to Expire: If you don't use DEL or set an expiration (using EXPIRE as seen in Implementing Expiration and TTL in Redis for Data Management), your memory usage will grow indefinitely.
  • Key Collisions: Always use a consistent naming convention. If you are tracking visitors for multiple endpoints, ensure your keys are namespaced (e.g., visitors:api_v1:login vs visitors:api_v1:signup) as discussed in Mastering Key Naming Conventions: Redis Best Practices.

Frequently Asked Questions

Does SADD slow down as the set grows? No. Adding a member to a set has a time complexity of O(1), meaning it takes the same amount of time regardless of whether you have 10 or 1,000,000 members.

Can I store objects in a Set? Redis Sets only store strings. If you need to track unique users by their full profile object, store a unique identifier (like a UUID or username) in the set, and keep the full object in a separate Hash.

What happens if I call SADD with the same ID? Redis simply returns 0 and does nothing, ensuring the set size remains accurate.

Recap

We’ve successfully moved from caching responses to tracking real-time user metrics. By leveraging the inherent deduplication of Redis Sets, we can count unique visitors with O(1) performance using SADD and SCARD. Remember to manage your memory by cleaning up keys once your analytics window closes.

Up next: We will dive into Atomic Operations, ensuring that even under high concurrency, our visitor counts remain perfectly accurate.

Similar Posts