A simple, lightweight URL shortener API built with Wrangler and Firebase Realtime Database.
At the beginning, I just needed a small piece of software to store links, so I designed this project to be suitable for personal use or small public instances. You can use it for any purpose, but some systems are intentionally designed to be lightweight, such as the URL hashing mechanism, which uses DJB2, and the protection against timing attacks on the admin key (to ensure both security and performance). Please keep this in mind and use it with caution if you plan to deploy it at scale.
If you only need the project for occasional work, feel free to use my public online instance; however, please keep my usage limits in mind in this case.
For those who need more resources for their instance, the project can be deployed to your own Cloudflare Workers account by clicking the deploy button below.
I host the project on the free plan. Usually, there are no resource issues because the software consumes very little in its steady state. However, the first request may consume more resources (e.g., CPU time) due to a cold start, but it stays within the limits of the free plan.
-
Provides protection by limiting the daily request quota and preventing burst traffic, such as spam or rapid-fire requests.
-
No duplicate URLs (saves space in your database).
-
No sign-up, no credit card, or other personal information required.
-
No logs are maintained to track user activity.
-
Highly configurable.
-
Store mappings in Firebase Realtime Database.
-
Minimal and fast REST API.
-
Serverless because it runs on a Cloudflare Worker with strict resource limits (Free plan).
This project is designed with GDPR compliance in mind:
-
No direct IP addresses or personal data are stored.
-
No user privacy information is logged.
-
Basic rate limiting is implemented by hashing IP addresses:
-
Hashing is done using
SHA-256, combined with a strong, secret salt. -
Hashes are stored only in an NoSQL database called KV.
-
IP hashes are automatically deleted after a configurable retention period.
-
-
No tracking, cookies, or analytics.
This ensures that no identifiable user data is collected, stored, or shared in any form.
The API is available here:
| Public endpoint: | Rate limit: | Owner: | Privacy policy: |
|---|---|---|---|
| https://nsh.nde-code.workers.dev/ | 1 req/sec, 10 new links/day | Nde-Code | privacy.md |
To use this API you can use:
-
JavaScript in the browser: CORS is enabled for all domains (but only for the posting URL, of course).
-
cURL from a terminal, for all endpoints: https://curl.se/
-
Postman (Recommended), for all endpoints: https://www.postman.com/
Create a short URL from a provided long URL. Saves the link to the database and applies rate limiting constraints.
| Field | Type | Description |
|---|---|---|
long_url |
string | Required. The original long URL you want to shorten. Must be valid. |
Note: The request will fail if the JSON body contains any unexpected fields other than
long_url, or if the URL exceeds the maximum configured length.
-
201 Created: URL successfully shortened and saved. -
200 OK: The URL was already shortened previously (returns existing short link). -
400 Bad Request: Invalid body, missinglong_url, unexpected field, or invalid URL format. -
409 Conflict: Hash Collision (different URL, same hash). -
429 Too Many Requests: Rate limit exceeded (either time-based or daily write limit). -
500 Internal Server Error: Wrong environment variable(s), config, generation failure or server error. -
503 Service Unavailable: KV Database quota exceeded (process rate limits), unable to read_url_counteror verify link existence. -
507 Insufficient Storage: Firebase database entry limit reached.
curl -X POST "https://your-worker.org.workers.dev/post-url" \
-H "Content-Type: application/json" \
-d '{"long_url": "https://nde-code.github.io/"}'{
"success": "https://your-worker.org.workers.dev/url/11i7yev0000000"
}Redirects the user to the original long URL associated with the provided short code.
| Parameter | Type | Description |
|---|---|---|
code |
string | Required. The unique short ID of the URL. |
-
301 Moved Permanently: Successful redirection (if the linkis_verifiedis true). -
302 Found: Successful redirection (if the linkis_verifiedis false). -
400 Bad Request: No valid ID provided in the path. -
404 Not Found: No link found with this ID in the database. -
500 Internal Server Error: Wrong environment variable(s), config or server error. -
503 Service Unavailable: The request timed out or the connection to the storage provider failed.
curl -i "https://your-worker.org.workers.dev/url/11i7yev0000000"Retrieve a paginated list of shortened links currently stored in the database.
Security: Requires a valid Admin/API key.
| Parameter | Type | Description |
|---|---|---|
count |
number | Number of links to retrieve (defaults to configured value, max is restricted). |
cursor |
string | The key of the last item from the previous page. |
-
200 OK: Successful query returning the URLs. -
400 Bad Request: Thecountorcursorparameter is invalid. -
401 Unauthorized: Invalid or missing API/Admin key. -
429 Too Many Requests: Rate limit exceeded. -
500 Internal Server Error: Wrong environment variable(s), config or server error. -
503 Service Unavailable: Unable to retrieve links from the database.
curl "https://your-worker.org.workers.dev/urls?count=2" \
-H "x-api-key: YOUR_ADMIN_KEY"{
"urls": {
"11i7yev0000000": {
"long_url": "https://nde-code.github.io/",
"post_date": "2024-05-12T10:00:00.000Z",
"is_verified": true
},
"vgsyqs00000000": {
"long_url": "https://www.google.com/",
"post_date": "2024-05-12T11:30:00.000Z",
"is_verified": false
}
},
"next_cursor": "vgsyqs00000000",
"has_more": true
}Mark a specific shortened URL as verified in the database.
Security: Requires a valid Admin/API key.
| Parameter | Type | Description |
|---|---|---|
code |
string | Required. The unique short ID of the URL. |
-
200 OK: Link verified successfully, or link was already verified. -
400 Bad Request: No valid ID provided in the path. -
401 Unauthorized: Invalid or missing API/Admin key. -
404 Not Found: No link found with this ID in the database. -
429 Too Many Requests: Rate limit exceeded. -
500 Internal Server Error: Wrong environment variable(s), config or server error. -
503 Service Unavailable: Temporary issue updating the database.
curl -X PATCH "https://your-worker.org.workers.dev/verify/11i7yev0000000" \
-H "x-api-key: YOUR_ADMIN_KEY"Delete a shortened URL from the database and decrement the global metadata counter.
Security: Requires a valid Admin/API key.
| Parameter | Type | Description |
|---|---|---|
code |
string | Required. The unique short ID of the URL. |
-
200 OK: Link successfully deleted. -
400 Bad Request: No valid ID provided in the path. -
401 Unauthorized: Invalid or missing API/Admin key. -
404 Not Found: No link found with this ID in the database. -
429 Too Many Requests: Rate limit exceeded. -
500 Internal Server Error: Wrong environment variable(s), config or server error. -
503 Service Unavailable: Temporary issue deleting the entry.
curl -X DELETE "https://your-worker.org.workers.dev/delete/11i7yev0000000" \
-H "x-api-key: YOUR_ADMIN_KEY"Recalculate and synchronize the metadata counter to reflect the actual number of URLs stored in the Firebase database. Useful for fixing race conditions or desyncs.
Security: Requires a valid Admin/API key.
-
200 OK: Counter successfully resynced (returns the new count). -
401 Unauthorized: Invalid or missing API/Admin key. -
429 Too Many Requests: Rate limit exceeded. -
500 Internal Server Error: Wrong environment variable(s), config or server error. -
503 Service Unavailable: Temporary issue communicating with the database.
curl -X PATCH "https://your-worker.org.workers.dev/sync-counter" \
-H "x-api-key: YOUR_ADMIN_KEY"{
"success": "Counter synchronized successfully.",
"new_count": 42
}To access protected endpoints, you must include an API or ADMIN key in the request headers using one of the following:
-
Authorization: Bearer <API_or_ADMIN_KEY> -
x-api-key: <API_or_ADMIN_KEY>
Of course, on my personal instance, trying to access these admin endpoints is forbidden.
Those interested in working on or launching this project from source using the Wrangler CLI can refer to the developer documentation by clicking here.
This project is licensed under the Apache License v2.0.
Created and maintained by Nde-Code.
Feel free to reach out for questions or collaboration, or open an issue or pull request and I'll be happy to help.