Creepy: The OSINT Tool That Proved We Were Broadcasting Our Lives
Hook
In 2011, a Greek security researcher built a tool that could map anyone's daily routine just by analyzing their tweets. The backlash was immediate, the privacy implications undeniable, and the tool itself became a cautionary tale about the arms race between OSINT tools and platform privacy controls.
Context
Before social media platforms locked down their APIs and disabled location sharing by default, the early 2010s were a goldmine for open-source intelligence gathering. Users casually geotagged photos from their homes, checked in at their favorite restaurants, and tweeted their exact coordinates without understanding the cumulative privacy implications. Every individual post seemed harmless, but aggregated together, they painted a detailed picture of someone's life: where they lived, where they worked, their daily routines, their relationships.
Creepy emerged in this environment as both a demonstration tool and a wake-up call. Built by Ioannis Kakavas, it automated what security researchers had been doing manually—collecting geotagged posts from Twitter, Instagram, and Flickr, then visualizing them on a map to reveal patterns invisible in isolated posts. The tool's name was deliberately provocative, forcing users to confront the creepy reality of what they were voluntarily broadcasting. It wasn't exploiting vulnerabilities; it was simply aggregating public data in a way that made privacy violations tangible. Within months of its release, Creepy became a staple in OSINT workshops and security conferences, demonstrating why metadata matters as much as content.
Technical Insight
Creepy's architecture reflects the plugin-based design patterns common in extensible desktop applications. At its core, the application implements a plugin system where each social media platform is abstracted as a separate plugin implementing a common interface. This allowed the tool to aggregate location data from heterogeneous APIs without coupling the core visualization logic to any specific platform.
The plugin interface likely followed a pattern similar to this:
class SocialMediaPlugin:
def __init__(self, credentials):
self.credentials = credentials
self.api_client = None
def authenticate(self):
"""Authenticate with platform API"""
raise NotImplementedError
def get_geotagged_posts(self, username, date_from=None, date_to=None):
"""Retrieve geotagged posts for target user
Returns:
List of dicts with structure:
{
'timestamp': datetime,
'latitude': float,
'longitude': float,
'content': str,
'platform': str,
'accuracy': str # GPS, IP-based, user-entered, etc.
}
"""
raise NotImplementedError
def supports_location_history(self):
"""Whether platform allows historical location queries"""
return True
The Twitter plugin would authenticate using OAuth 1.0a (the standard at the time), then query the user timeline endpoint filtering for tweets with coordinates. The critical insight was that Twitter's API exposed precise GPS coordinates when users enabled location services, not just city-level data:
def get_geotagged_posts(self, username, date_from=None, date_to=None):
posts = []
tweets = self.api_client.GetUserTimeline(
screen_name=username,
count=200,
include_rts=False
)
for tweet in tweets:
if tweet.geo or tweet.coordinates:
# Coordinates are in [lat, lon] format
coords = tweet.coordinates['coordinates'] if tweet.coordinates else tweet.geo['coordinates']
posts.append({
'timestamp': datetime.strptime(tweet.created_at, '%a %b %d %H:%M:%S +0000 %Y'),
'latitude': coords[1],
'longitude': coords[0],
'content': tweet.text,
'platform': 'twitter',
'accuracy': 'GPS',
'place': tweet.place.full_name if tweet.place else None
})
return self._filter_by_date(posts, date_from, date_to)
The application used PyQt for its GUI, providing a desktop interface that displayed collected locations on an embedded map (likely using OpenStreetMap tiles or Google Maps API). The visualization component would cluster nearby points, draw movement patterns between locations, and identify frequently visited places algorithmically by analyzing temporal and spatial clustering.
What made Creepy particularly effective was its export functionality. Rather than being a standalone analysis tool, it could export to KML (Keyhole Markup Language) and CSV, enabling integration with professional GIS tools. This meant security researchers could perform sophisticated geospatial analysis, overlay location data with other intelligence sources, or present findings in formats familiar to law enforcement and corporate security teams.
The data persistence layer likely used SQLite for local storage, caching fetched posts to avoid rate limiting and enable offline analysis. This architectural decision reflected the reality of working with rate-limited APIs—you fetch once, analyze repeatedly. The database schema would track not just locations but also API query history, rate limit status, and plugin configuration, enabling the application to resume interrupted queries and respect platform-specific throttling rules.
Gotcha
Creepy is functionally dead, and that's the most important thing to understand before considering it for anything beyond historical study. The repository has been explicitly unmaintained since 2016, and the API landscape that made it possible no longer exists. Twitter deprecated the API endpoints Creepy relied on, introduced stricter rate limits, and changed OAuth requirements. Instagram moved to Facebook Graph API and severely restricted access to user data, requiring app review processes that OSINT tools rarely pass. Even if you updated the code, most social platforms now disable location sharing by default, meaning the data simply isn't there anymore.
The codebase itself carries the technical debt of mid-2010s Python development. Dependencies like older PyQt versions, deprecated OAuth libraries, and unmaintained API wrappers create a minefield of compatibility issues. Security vulnerabilities in these outdated dependencies make the tool actively dangerous to run on modern systems. The GUI framework assumptions don't translate cleanly to Python 3, and attempts to modernize the codebase would essentially require a complete rewrite. This isn't a tool you can clone, pip install, and run—it's archaeological code that documents what was once possible but no longer is.
Verdict
Use if: You're researching the history of OSINT techniques, teaching a course on privacy implications of social media, or need reference code for understanding plugin architectures in desktop applications. The codebase serves as a valuable historical artifact demonstrating how dramatically the API economy has shifted toward restrictive access models. It's also useful for understanding why modern privacy defaults matter—Creepy's effectiveness drove platform changes that made users safer.
Skip if: You need a functional OSINT tool for actual intelligence gathering, security research on current platforms, or any production use case whatsoever. The tool simply doesn't work anymore, and attempting to revive it would require more effort than building a new tool from scratch using modern APIs, web scraping techniques, or alternative data sources. Look instead to actively maintained OSINT frameworks like Maltego, SpiderFoot, or Recon-ng that adapt to the constantly shifting landscape of social media APIs and privacy controls.