FeaturesTemplatesShowcaseTownie
AI
BlogDocsPricing
Log inSign up
lightweight

lightweight

bragreel

Public
Like
1
bragreel
Home
Code
7
frontend
1
routes
9
utils
6
README.md
C
cache.tsx
H
index.tsx
C
publish.tsx
Branches
11
Pull requests
Remixes
1
History
Environment variables
1
Val Town is a collaborative website to build and scale JavaScript apps.
Deploy APIs, crons, & store data – all from the browser, and deployed in milliseconds.
Sign up now
Code
/
README.md
Code
/
README.md
Search
5/22/2025
README.md

Notion Web Utilities API

A comprehensive API for enhancing Notion pages with web content utilities. This API provides several endpoints to extract and update information from web pages to Notion, including favicons, page titles, domain information, and embeds. The system includes automated cron jobs for periodic data synchronization and blob storage for efficient caching.

Project Overview

This API serves as a bridge between web content and Notion pages, allowing you to:

  • Extract favicons from websites and set them as Notion page icons
  • Extract page titles from websites and update Notion page titles
  • Extract domain information from URLs in Notion pages
  • Add URL embeds to Notion pages
  • Generate showcases of web content
  • Cache Notion database data for improved performance
  • Automatically publish content based on status changes

The API is built using Hono, a lightweight web framework, with modular routes for better organization and maintainability. It includes automated background processes and intelligent caching to optimize performance and reduce API calls.

Project Structure

/
├── index.tsx              # Main Hono app entry point with route mounting
├── cache.tsx (cron)       # Cron job for updating cached Notion data
├── publish.tsx (cron)     # Cron job for auto-publishing content
├── routes/                # Directory for API route modules
│   ├── cache.tsx          # Cache management endpoints
│   ├── domain.tsx         # Domain extraction endpoint
│   ├── embed.tsx          # URL embed endpoint
│   ├── favicon.tsx        # Favicon extraction endpoint
│   ├── showcase.tsx       # Content showcase endpoint
│   ├── showcaseHTML.tsx   # HTML showcase endpoint
│   ├── test-domain.tsx    # Domain testing endpoint
│   └── title.tsx          # Title extraction endpoint
├── utils/                 # Utility functions
│   ├── extractValuesFromNotionProperties.tsx # Notion property parsers
│   ├── getDomain.tsx      # Function to extract domain from URL
│   ├── getTitle.tsx       # Function to extract title from URL
│   └── HTMLhelpers.tsx    # HTML processing utilities
├── frontend/              # Frontend assets
│   └── index.html         # Main HTML template
└── README.md              # This documentation file

Architecture Overview

Hono API Framework

The application uses Hono as its web framework, providing a lightweight and fast HTTP server. The main entry point (index.tsx) creates a Hono app instance and mounts modular route handlers:

// Main app setup const app = new Hono(); app.use(trimTrailingSlash()); // Mount route modules app.route("/cache", cache); app.route("/domain", domain); app.route("/embed", embed); app.route("/title", title); app.route("/favicon", favicon); // ... other routes // Error handling for debugging app.onError((err, c) => { console.error("Error:", err); throw err; }); export default app.fetch; // Entry point for HTTP vals

Each route is implemented as a separate Hono router module in the /routes directory, allowing for:

  • Modular organization: Each endpoint has its own file with focused functionality
  • Independent testing: Routes can be tested in isolation
  • Easy maintenance: Changes to one endpoint don't affect others
  • Clear separation of concerns: Each route handles specific web utility functions

Cron Jobs for Automated Data Management

The system includes two automated cron jobs that run periodically to manage Notion data:

1. Cache Update Cron (cache.tsx)

  • Purpose: Periodically refreshes cached Notion database data
  • Frequency: Runs on a scheduled interval (configurable in Val Town UI)
  • Process:
    1. Finds cached database blob using key pattern cache--db--{databaseId}
    2. Queries Notion database for pages with "Published" status
    3. Extracts relevant properties (Name, URL, Publication status)
    4. Updates the blob storage with fresh data
    5. Maintains cache consistency without manual intervention
// Key pattern for finding cached databases const blobKey = ["cache", "db"].join("--"); const blobKeys = await blob.list(blobKey); const databaseId = blobKeys[0].key.split("--").pop(); // Query Notion with filter const response = await notion.databases.query({ database_id: databaseId, filter: { property: "Publication status", select: { equals: "Published" } } });

2. Publishing Cron (publish.tsx)

  • Purpose: Automatically publishes content marked as "Ready to publish"
  • Frequency: Runs on a scheduled interval
  • Process:
    1. Finds pages with "Ready to publish" status
    2. Updates their status to "Published"
    3. Enables automated content workflow without manual intervention

Blob Storage Caching System

The application uses Val Town's blob storage as an intelligent caching layer to optimize performance and reduce Notion API calls:

Cache Architecture

Blob Key Structure: cache--db--{databaseId}

  • cache: Identifies the blob's purpose
  • db: Indicates it's a database cache
  • {databaseId}: The specific Notion database being cached

Cache Workflow

  1. Cache Initialization (/cache POST endpoint):

    // Extract database ID from a page const page = await notion.pages.retrieve({ page_id: pageId }); const parentId = page.parent.database_id; // Create structured cache key const blobKey = ["cache", "db", parentId].join("--"); // Initialize cache if it doesn't exist if (!await blob.getJSON(blobKey)) { await blob.setJSON(blobKey, { ok: true }); }
  2. Cache Updates (via cron job):

    • Automatically refreshes cached data every interval
    • Maintains data freshness without manual intervention
    • Reduces load on Notion API by batching updates
  3. Cache Retrieval (/cache GET endpoint):

    // Find cache using key fragment const blobKeys = await blob.list("cache--db"); const cachedData = await blob.getJSON(blobKeys[0].key); return c.json(cachedData);

Benefits of This Caching Strategy

  • Performance: Instant data retrieval from blob storage vs. API calls
  • Rate Limiting: Reduces Notion API usage, avoiding rate limits
  • Reliability: Cached data available even if Notion API is temporarily unavailable
  • Cost Efficiency: Fewer API calls reduce potential costs
  • Scalability: Can serve multiple requests from cache without additional API load

API Endpoints

GET /

Returns a list of available endpoints.

Example Response:

API Gateway - Available endpoints: /cache, /domain, /title, /favicon, /test-domain, /embed, /showcase, /showcase-html

Cache Management Endpoints

POST /cache

Initializes caching for a Notion database by creating a blob storage entry.

Request Body:

{ "data": { "id": "notion-page-id" } }

Process:

  1. Retrieves the page from Notion
  2. Extracts the parent database ID
  3. Creates a cache blob with key pattern: cache--db--{databaseId}
  4. Returns the cache status

Success Response:

{ "ok": true }

GET /cache

Retrieves cached database data from blob storage.

Success Response:

{ "success": true, "count": 25, "pages": [ { "id": "page-id", "name": "Page Title", "url": "https://example.com", "status": "Published" } ] }

GET /cache/:id

Retrieves cached data for a specific database ID.

Parameters:

  • id: The database ID to retrieve cache for

Content Extraction Endpoints

POST /favicon

Extracts a favicon from a URL in a Notion page and updates the page icon.

Request Body:

{ "data": { "id": "notion-page-id" } }

Success Response:

{ "success": true, "message": "Favicon found and Notion page updated", "pageId": "notion-page-id", "url": "https://example.com", "faviconUrl": "https://example.com/favicon.ico" }

Error Response:

{ "success": false, "error": "Failed to retrieve Notion page", "message": "Error details", "pageId": "notion-page-id" }

POST /favicon/notion (Legacy Endpoint)

Handles Notion webhooks to extract a favicon from a URL and update the corresponding Notion page with the favicon.

Request Body:

{ "pageId": "notion-page-id" }

Success Response:

{ "success": true, "message": "Favicon found and Notion page updated", "pageId": "notion-page-id", "url": "https://example.com", "faviconUrl": "https://example.com/favicon.ico" }

POST /domain

Extracts the domain from a URL property in a Notion page and updates the Domain property.

Request Body:

{ "data": { "id": "notion-page-id" } }

Success Response: Returns the updated Notion page object.

GET /domain

Test endpoint to verify the domain extraction API is working.

Response:

Hello World!

POST /title

Extracts the title from a URL in a Notion page and updates the page title.

Request Body:

{ "data": { "id": "notion-page-id" } }

Success Response: Returns the updated Notion page object.

Error Response:

{ "error": "Error message", "stack": "Error stack trace" }

GET /title

Test endpoint to verify the title extraction API is working.

Response:

Title Extractor API is running!

GET /title/test

Test endpoint for the getTitle function.

Query Parameters:

  • url: The URL to extract the title from

Success Response:

{ "url": "https://example.com", "title": "Example Domain" }

POST /embed

Adds an embed block with the provided URL to a Notion page.

Request Body:

{ "pageId": "notion-page-id", "url": "https://example.com" }

GET /showcase and /showcase-html

Endpoints for showcasing content, likely for preview purposes.

Implementation Details

Favicon Extraction

The favicon endpoint uses multiple strategies to extract a favicon:

  1. First tries Google's Favicon API for reliable results
  2. If that fails, tries the standard /favicon.ico path
  3. If that fails, it parses the HTML to find favicon link tags
  4. Returns the favicon URL and updates the Notion page icon
  5. Falls back to a globe emoji (🌐) if no favicon can be found

Title Extraction

The title extraction is sophisticated and handles various edge cases:

  1. Special handling for YouTube URLs using their oEmbed API
  2. Special handling for news sites with anti-scraping measures
  3. Multiple fallback strategies including:
    • OpenGraph meta tags
    • Twitter card meta tags
    • Standard title tags
    • Google search results
    • URL slug parsing

Domain Extraction

Extracts the domain (including protocol) from a URL:

  1. Handles URLs without protocol by adding https:// as default
  2. Parses the URL to extract the origin (protocol + hostname)
  3. Updates the Domain property in the Notion page

Environment Variables

This API requires the following environment variable:

  • NOTION_API_KEY: Your Notion API integration token

You'll need to create an integration in the Notion workspace and grant it access to the relevant pages or databases.

Usage Examples

Updating a Notion Page with a Website Favicon

curl -X POST https://your-api-url/favicon \ -H "Content-Type: application/json" \ -d '{"data":{"id":"your-notion-page-id"}}'

Extracting a Title from a URL

curl -X GET "https://your-api-url/title/test?url=https://example.com"

Updating a Notion Page with a Website Title

curl -X POST https://your-api-url/title \ -H "Content-Type: application/json" \ -d '{"data":{"id":"your-notion-page-id"}}'

Adding New Routes

To add a new route:

  1. Create a new file in the /routes directory
  2. Export a Hono router with your endpoint handlers
  3. Import and mount the router in index.tsx

Example:

// In /routes/newEndpoint.ts import { Hono } from "npm:hono@3"; const router = new Hono(); router.get("/", (c) => { return c.json({ message: "New endpoint" }); }); export default router; // In index.tsx import newEndpoint from "./routes/newEndpoint.tsx"; // Mount the new router app.route("/new-endpoint", newEndpoint);

Error Handling

The API includes comprehensive error handling:

  • Detailed error messages for debugging
  • Fallback strategies for common failure scenarios
  • Error unwrapping to see original error details

Notion Integration

This API integrates with the Notion API to:

  1. Retrieve page data including properties like URL and Domain
  2. Update page properties with extracted information
  3. Set page icons using extracted favicons
  4. Add embed blocks to pages

The integration requires a Notion API key and appropriate permissions to access and modify the pages.

FeaturesVersion controlCode intelligenceCLI
Use cases
TeamsAI agentsSlackGTM
ExploreDocsShowcaseTemplatesNewestTrendingAPI examplesNPM packages
PricingNewsletterBlogAboutCareersBrandhi@val.townStatus
X (Twitter)
Discord community
GitHub discussions
YouTube channel
Bluesky
Terms of usePrivacy policyAbuse contact
© 2025 Val Town, Inc.