Close
0%
0%

Headless Bluesky OSINT Radar

Collecting public Bluesky posts for select keywords, storing metadata in SQLite and generating daily reports for analysis on Linux Mint.

Similar projects worth following
54 views
0 followers
A project for collecting, storing and analyzing public Bluesky activity around selected keywords. The goal is to build a small, reliable, always-on backend appliance which quietly gathers social signals over time. The Linux Mint machine acts as a headless collection node for polling the ATProto API for chosen topics, normalizing the results, storing useful metadata in SQLite and generating regular reports for later analysis. Each collector run will also be logged so the project can track uptime, failures, duplicates and collection volume over time.

A Linux Mint-based backend appliance for collecting, storing and analyzing Bluesky activity around selected keywords. The project is designed to run continuously as a headless collection node, gathering activity over time from the ATProto ecosystem and preserving them in a local SQLite database for later analysis.

At its core, the system polls the ATProto API for chosen topics, processes the returned posts and stores useful information such as text content, handles, engagement, keywords and response data. Each run is logged so the appliance can track not only what it collected, but also how reliably the device operated. This includes timestamps, success or failure states, duplicates, inserted records, total volume and errors.

The goal is to build a small, reliable social signal collection appliance operating independently on a local network. Rather than depending on an external analytics platform, the project emphasizes simplicity and transparency; a Linux Mint machine, Flask API, SQLite database and scheduled collection.

This project is especially useful for long-term observation of public conversation patterns. By collecting posts containing particular keywords over months, the system can support later analysis of topics, authors, engagement, trends, health and changes in public interest. The stored data will eventually be exported into reports and frontend D3.js graphics.

The project is intentionally built in phases. The first phase focuses on data collection and storage. The second phase adds automation, uptime tracking and regular report generation. Later phases include dashboards, trend detection, comparisons, frequency analysis and data exports.

  • Verifying The Underlying Data Pipeline Is Working Correctly

    Bret Bernhoft05/28/2026 at 00:58 0 comments

    Instead of building a polished dashboard next, I wanted to confirm the underlying data pipeline was working. So this evening I inspected the SQLite database directly to get a quick row count across four tables.

    Using the terminal, I opened the project database with:

    sqlite3 data/radar.sqlite 

    Then I ran a small SQL query to count the rows in the core tables:

    SELECT 'posts' AS table_name, COUNT(*) AS rows FROM posts 
    UNION ALL 
    SELECT 'authors', COUNT(*) FROM authors
    UNION ALL
    SELECT 'matches', COUNT(*) FROM post_keyword_matches
    UNION ALL
    SELECT 'runs', COUNT(*) FROM collection_runs; 

    The results were encouraging:

    posts|62952
    authors|30138
    matches|294065
    runs|497 

    Which means the system has collected 62,952 posts, tracked 30,138 authors, recorded 294,065 keyword matches and completed 497 collection runs. For a local project running on my own hardware, this is a healthy amount of data to start analyzing.

    However these stats are slightly skewed because the system had two restarts during the collection period. Those restarts affect how cleanly the run count and collection continuity should be interpreted. The totals are still useful, but they should not be treated as a perfectly uninterrupted measurement window. In future versions, I will add restart tracking, run session IDs or metadata for distinguishing between normal collection cycles and interrupted sessions.

    Overall, this was a good validation checkpoint. The collector is producing real data, the SQLite structure is easy to inspect and the next step is to turn these raw counts into visual analysis, trends and eventually a more complete OSINT dashboard.

  • Always-On Headless Bluesky OSINT Radar Node Launched

    Bret Bernhoft05/20/2026 at 23:36 0 comments

    Today I reached the first real milestone for this project; launching an OSINT appliance running in my homelab, collecting public Bluesky activity for specific keywords and storing the results in SQLite for later review.

    A major motivator for this project is wanting to experiment with headless machines on my local network, quietly collecting public conversation data over time. The technology stack is simple, consisting of Linux Mint, Python, Flask, SQLite, the ATProto API and eventually D3.js for visualization.

    The first version of this project started as a collector script with output available in the terminal. It loaded credentials from a .env file, authenticated with Bluesky, pinged the ATProto search API and normalized the returned posts into records. 

    From there, I moved the project into a more always-on mode. I added a Flask server and SQLite database. The Flask app now owns the database, exposes various endpoints and runs scheduled collection automatically. The collection interval is currently set to every 20 minutes.

    The database schema is designed around four core tables. Those being posts, authors, post_keyword_matches and collection_runs. This structure prevents exact duplicate posts by using the Bluesky post URI as the primary key, while preserving useful repeated observations over time.

    Ultimately, the OSINT radar node is collecting. The database is clean. The appliance is alive.

  • Removed Original Project Files From Raspberry Pi 5 Computer

    Bret Bernhoft05/14/2026 at 01:50 0 comments

    Today’s progress focused on removing my first attempt at developing this application on a Raspberry Pi 5, while confirming the existing Pi-hole installation remained healthy and unaffected.

    The first step was to verify whether any application databases still existed on the RPi 5 system. A search was run for common SQLite database file types. The results showed several databases including Pi-hole databases, Mesa graphics cache files, Linux system databases and Docker metadata. None of these were related to the deleted project, so no unnecessary database files were removed.

    Next, systemd services were reviewed to identify anything running from the old application. This revealed the Headless Bluesky OSINT Radar service was still installed and active. The service definition was inspected, indicating the presence of the original project directory, a related Python virtual environment, a loaded .env file and app.py script. This confirmed the exact project path and service file needing to be removed.

    The cleanup plan included stopping and disabling the systemd service, deleting the service file, reloading systemd and removing the remaining project directory. Additional commands were used to check for any leftover files, running processes, Docker containers and Docker volumes from the old project.

    After completely removing the old application, Pi-hole was checked to ensure the Raspberry Pi’s DNS filtering service was still functioning correctly. The service was confirmed to be active and running. A DNS test also returned a successful response, confirming the local DNS resolution through Pi-hole was working properly.

    Moving forward, instead of using a Raspberry Pi 5 computer, this project is utilizing a Linux Mint machine. Which will be documented in future log entries and project details.

View all 3 project logs

Enjoy this project?

Share

Discussions

Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates