A work in progress Next.js app for scraping queue time data from SSSB, Stockholm's largest student accommodation service. 🏢
Built as a hobby project and learning experience. Originally to familiarise myself with Golang and Golang ORM libraries + Postgres. However, the new version is written in Next.js + TypeScript to work towards a monorepo SSSB analytics dashboard.
Finding student accommodation in Stockholm is challenging. Those who secure a first-hand lease typically do so through SSSB, the Stockholm Student Unions' Central Organization student housing service, after spending a year or two in their queueing system.
Once you start studying and join a student union, you can begin collecting queue points. You can apply from a list of available housing units whenever you wish, and more queue points generally give you access to better accommodation options (the applicant with the most queue points is offered the flat).
This project was created to collect data from the SSSB website to gain deeper insight into these factors and better understand the dynamics of the queueing system (seasonal fluctuations, trends, etc.).
Currently, only the scraping trigger API is up and working. The API provides endpoints to scrape SSSB apartment listings and their details regarding queue times. You can trigger full scrapes of all apartments or scrape individual apartments by their reference ID.
The scraper uses Puppeteer and chromium-min to handle the JavaScript-rendered content on the SSSB website. It scrapes from:
- Listing page:
https://minasidor.sssb.se/lediga-bostader/ - Individual apartment pages:
https://minasidor.sssb.se/lediga-bostader/lagenhet/?refid=...
- Node.js 18+
- pnpm (package manager)
git clone <repository-url>
cd sssbpp
pnpm installNote: The postinstall script will automatically install Playwright's Chromium browser. This may take a few minutes on first install.
Create a .env.local file in the root directory with your API key and database URL:
API_KEY=your-secret-api-key-here
DATABASE_URL=postgresql://user:password@host:port/databaseAll API endpoints require authentication via the X-API-Key header or Authorization: Bearer <key> header.
pnpm devThe application will be available at http://localhost:3000
After setting up your DATABASE_URL in .env.local, push your schema to the database:
pnpm db:pushThis will create the tables directly from your schema. For production, you can generate and run migrations:
pnpm db:generate
pnpm db:migrateOr use Drizzle Studio to view your database:
pnpm db:studiopnpm build
pnpm startAll endpoints require API key authentication. Include your API key in the request headers:
X-API-Key: your-api-keyorAuthorization: Bearer your-api-key
Returns a list of all available apartment reference IDs (refIds) without scraping full details. This is faster than the full scrape endpoint.
Headers:
X-API-KeyorAuthorization: Bearer <key>
Response:
{
"success": true,
"count": 42,
"refIds": ["refId1", "refId2", ...],
"timestamp": "2024-01-01T12:00:00.000Z"
}Scrapes all available apartments from SSSB.
Headers:
X-API-KeyorAuthorization: Bearer <key>
Response:
{
"success": true,
"count": 42,
"apartments": [...],
"timestamp": "2024-01-01T12:00:00.000Z"
}Scrapes a single apartment by its reference ID.
Headers:
X-API-KeyorAuthorization: Bearer <key>
Response:
{
"success": true,
"apartment": {
"objNr": "...",
"refId": "...",
"hood": "...",
"aptType": "...",
"address": "...",
"aptNr": "...",
"availableUntil": "...",
"bestPoints": 1234,
"bookers": 42,
"infoLink": "...",
"moveIn": "...",
"rent": 5000,
"sqm": 25,
"special": ""
},
"timestamp": "2024-01-01T12:00:00.000Z"
}The application uses Drizzle ORM with PostgreSQL (via Supabase) to store scraped apartment data. The database includes:
- apartments: Current state of each apartment (upserted on each scrape)
- scrapes: Historical tracking of queue points and bookers over time
All scrape endpoints automatically save data to the database.
- Setting up scheduled scraping via Vercel Cron Jobs or external cron services
- Building a frontend to browse and visualize the scraped data
- Building analytics and insights into queue point trends