DEV Community

Cover image for How I Built Wikibeem: Turning ClickUp Docs into Professional Documentation Sites
Toumi abderrahmane
Toumi abderrahmane

Posted on

How I Built Wikibeem: Turning ClickUp Docs into Professional Documentation Sites

A solo dev journey from frustration to product launch

The Frustration That Started It All

I love ClickUp. It's where my team lives — tasks, docs, wikis, everything connected.

But every time I needed to share documentation with a client, I hit the same wall:

doc.clickup.com/d/2kxuepwx-192

That URL. That ugly, branded, unprofessional URL.

Clients would ask: "Why are we using ClickUp? Can you put this on your website?"

So I'd spend hours:

  • Exporting to PDF (formatting breaks)
  • Copy-pasting to Notion (links break)
  • Rebuilding in GitBook (context lost)

I found workarounds like Cloakist, but they just proxy the ClickUp page — clients could still click around and find internal stuff.

Then I went digging.

I searched Reddit, ClickUp forums, and feedback boards. Turns out I wasn't alone:

"Shared doc.clickup.com with a prospect. They thought we use ClickUp internally and bailed." — r/clickup

"Want to share the onboarding section. Can't without exposing the entire task roadmap." — feedback.clickup.com

"Docs export breaks embeds, bullets vanish. Recreating in Notion costs 4 hours of work." — Agency PM on Reddit

Hundreds of people had the same frustration. Agencies, SaaS teams, freelancers — all stuck with the same problem.

One night, I thought: What if I could solve this for myself AND for them?

That's how Wikibeem was born.


The Tech Stack

I built Wikibeem as a solo developer over several months. Here's what powers it:

Frontend

  • Next.js 16 with App Router
  • React 19
  • Tailwind CSS 4
  • Server and Client Components for optimal performance

Backend

  • Next.js API Routes — no separate backend needed
  • PostgreSQL with Prisma ORM
  • Vercel for hosting and edge functions

Authentication & Payments

  • NextAuth v5 (beta) — credentials + OAuth ready
  • Paddle — for subscriptions (handles global taxes automatically)

The ClickUp Integration

  • ClickUp API v3 — OAuth 2.0 flow
  • Axios for API calls
  • Custom sync engine that handles nested pages, wikis, and doc hierarchies

Content Processing

  • Marked — Markdown to HTML conversion
  • Cheerio — HTML manipulation and cleaning
  • Turndown — HTML to Markdown when needed

Search & SEO

  • Fuse.js — client-side fuzzy search
  • Custom SEO per site and per document
  • Auto-generated sitemaps

Domain Management

  • Vercel SDK — programmatic custom domain setup
  • Automatic SSL certificates

Internationalization

  • next-intl — 9 languages supported
  • English, French, German, Spanish, Portuguese, Italian, Russian, Arabic, Chinese

The Architecture

Here's how Wikibeem works under the hood:

┌─────────────────┐     OAuth      ┌─────────────────┐
│   ClickUp API   │◄──────────────►│    Wikibeem     │
│   (Your Docs)   │                │    (Next.js)    │
└─────────────────┘                └────────┬────────┘
                                            │
                    ┌───────────────────────┼───────────────────────┐
                    │                       │                       │
              ┌─────▼─────┐          ┌──────▼──────┐         ┌──────▼──────┐
              │ PostgreSQL │          │   Vercel    │         │   Paddle    │
              │  (Prisma)  │          │  (Domains)  │         │ (Payments)  │
              └───────────┘          └─────────────┘         └─────────────┘
Enter fullscreen mode Exit fullscreen mode

The Data Model

User
 └── Workspace (ClickUp connection)
      └── Site (your docs website)
           ├── Documents (synced from ClickUp)
           │    └── Children (nested pages)
           ├── Domain (custom domain)
           ├── Theme (colors, logo)
           └── SEO Settings
Enter fullscreen mode Exit fullscreen mode

The Hardest Part: Syncing ClickUp Docs

ClickUp's API is... interesting. Docs can have:

  • Nested pages
  • Wikis with their own structure
  • Content in different formats (JSON blocks, Markdown, HTML)

My sync engine had to:

  1. Fetch all docs from a workspace
  2. Recursively process pages and their children
  3. Convert content to clean HTML
  4. Build a hierarchy with parent-child relationships
  5. Generate unique slugs for URLs
  6. Handle updates without creating duplicates

The trickiest bug? ClickUp sometimes returns a page that's actually a root doc. Took me days to figure out why I had duplicate content everywhere.

// The fix: Track root doc IDs and filter them out
const rootDocIds = new Set(docs.map(d => d.id))

// When processing pages, skip if it's actually a root doc
if (rootDocIds.has(page.id)) {
  continue // This page is a doc, not a child page
}
Enter fullscreen mode Exit fullscreen mode

Performance Optimization

The first version was slow. Each document checked slug uniqueness with a database query.

For 100 pages = 100+ database round trips. 💀

The fix: In-memory slug tracking.

const existingSlugs = new Set<string>()

// Instead of: await prisma.document.findUnique(...)
// Now: existingSlugs.has(slug)

existingSlugs.add(newSlug) // Track immediately
Enter fullscreen mode Exit fullscreen mode

Sync time dropped from 30+ seconds to under 10.


Custom Domains: The Magic

This was the feature I was most excited about.

Using Vercel's SDK, I can programmatically:

  1. Add a domain to the project
  2. Return DNS records for the user to configure
  3. Verify domain ownership
  4. Auto-provision SSL certificates
const vercel = new Vercel({ accessToken: process.env.VERCEL_TOKEN })

// Add domain
await vercel.projects.addProjectDomain({
  idOrName: projectId,
  requestBody: { name: 'docs.yourcompany.com' }
})

// Get verification records
const config = await vercel.domains.getDomainConfig({
  domain: 'docs.yourcompany.com'
})
Enter fullscreen mode Exit fullscreen mode

The user adds a CNAME record, clicks "Verify," and boom — their docs are live on their domain with HTTPS.


Things I'd Do Differently

1. Write More Tests

The sync logic is complex. I've caught bugs manually that tests would have caught faster.

2. Ship Faster

I spent too long on "perfect" features. Should have launched with 50% of what I have now.


What's Next

  • Real-time sync — webhook integration with ClickUp
  • Analytics — see which docs people read
  • Password-protected docs — for private client portals
  • More themes
  • API access — for power users

Try It Yourself

Wikibeem is live at wikibeem.com.

Connect your ClickUp workspace, sync your docs, add your domain.

Under 5 minutes to a professional documentation site.

I'm building this in public and genuinely want feedback. What features would make this useful for you? What's missing?

DM me on Twitter/X or LinkedIn.

Let's build this together.

Top comments (0)