KOKOLIKOOO is Kacy Farms' poultry brand, serving hotels, supermarkets, and restaurants across Kigali, Rwanda. We deliver fresh, chilled chicken — 150 tons per year, always on time.
- Brand Name: KOKOLIKOOO
- Company: Kacy Farms (Kacy Ltd)
- Website: https://kacy.rw
| Page | URL | Description |
|---|---|---|
| Home | / |
Products, quality, certifications, FAQ |
| About | /about/ |
Company story, business units, values |
| Contact | /contact/ |
Contact form, phone, location map |
| Blog | /blog/ |
Poultry sourcing insights for Kigali kitchens |
| Privacy Policy | /privacy-policy/ |
Data handling policy |
| 404 | /404.html |
Custom error page |
Nine commercial and informational pages for chicken meat. They are not in the navbar by design — they are reached from the sitemap, from contextual links on the homepage and blog, and from the cross-links on each other. Adding them to the navbar would push the core four nav items out of a sensible hierarchy.
| Page | URL | Primary intent |
|---|---|---|
| Chicken meat hub | /chicken-meat/ |
Product range, the commercial entry point |
| Chicken cuts | /chicken-cuts/ |
"chicken cuts explained", weights and yields |
| Processing | /chicken-meat-processing/ |
On-site processing, cut-to-spec |
| Delivery | /chicken-meat-delivery/ |
Delivery coverage, standing orders |
| Wholesale | /wholesale-chicken-supply/ |
B2B specs, volumes, scheduling |
| Buyer's guide | /chicken-meat-guide/ |
Weights, yields, spotting fresh meat |
| How to cook | /how-to-cook-chicken/ |
Prep, 74 °C rule, times per cut |
| Nutrition | /chicken-nutrition/ |
Protein/calories/fat per cut |
| Safety | /fresh-chicken-safety/ |
Storage, shelf life, thawing |
Each page ships a @graph of Organization → WebSite → LocalBusiness → WebPage →
page-specific node (ItemList, Service, or HowTo) → BreadcrumbList → FAQPage, with
visible FAQ answers that match the schema. No prices are published anywhere, so
there is nothing to become stale.
The contact form posts to /api/contact, a Cloudflare Pages Function that
validates the submission and relays it through the Resend HTTP API to
info@kacy.rw. There is no third-party form service in the loop.
- Function:
functions/api/contact.js(Pages Functions routing, sofunctions/api/contact.js→POST /api/contact). - Client:
js/contact-form.js, progressive enhancement — the form posts normally without JavaScript and upgrades tofetchwith it. - Spam controls: honeypot field, minimum fill time, payload size cap, and a best-effort per-isolate throttle. The throttle is in-memory, so it is a speed bump rather than a hard limit. Enforce real limits at the edge (WAF rule or Turnstile) if the endpoint gets abused.
- Note: message bodies are deliberately truncated before email. Very long submissions are cut down rather than sent in full.
Set the API key as a Pages secret — never in wrangler.toml:
npx wrangler pages secret put RESEND_API_KEY --project-name kacywrangler.toml holds the non-secret overrides:
| Variable | Default | Purpose |
|---|---|---|
MAIL_FROM |
KOKOLIKOOO Website <website@kacy.rw> |
Resend verified sender. Must be a domain verified in Resend, otherwise the API rejects it. |
MAIL_TO |
info@kacy.rw |
Where enquiries land. |
ALLOWED_ORIGINS |
https://kacy.rw,https://www.kacy.rw |
Comma-separated CORS allowlist. Add preview domains when testing. |
Locally, python -m http.server will not run the function. Use Wrangler so
/api/contact resolves:
npx wrangler pages dev .KACY/
├── index.html # Home page
├── 404.html # Error page
├── about/
│ └── index.html # About page
├── blog/
│ ├── index.html # Blog index
│ ├── choose-chicken-supplier-kigali/index.html
│ ├── whole-chicken-vs-cuts/index.html
│ └── cold-chain-fresh-chicken/index.html
├── chicken-meat/index.html # Product hub
├── chicken-cuts/index.html # Cut reference
├── chicken-meat-processing/ # Processing capabilities
├── chicken-meat-delivery/ # Delivery coverage
├── wholesale-chicken-supply/ # B2B supply
├── chicken-meat-guide/ # Buyer's guide
├── how-to-cook-chicken/ # Cooking guide
├── chicken-nutrition/ # Nutrition facts
├── fresh-chicken-safety/ # Food safety guide
├── contact/
│ └── index.html # Contact page
├── privacy-policy/
│ └── index.html # Privacy policy
├── components/
│ ├── navbar.html # Navigation (inlined into every page)
│ └── footer.html # Footer (inlined into every page)
├── functions/
│ └── api/
│ └── contact.js # Pages Function: POST /api/contact -> Resend
├── css/
│ ├── style.css # Custom styles (self-hosted font, utilities)
│ ├── tailwind.css # Built Tailwind CSS (generated)
│ └── input.css # Tailwind entry point
├── js/
│ ├── main.js # Mobile menu + hydration (no content fetch)
│ └── contact-form.js # Progressive form submission
├── assets/
│ ├── fonts/google-sans-latin.woff2 # Self-hosted Google Sans (latin subset)
│ └── images/ # WebP/AVIF assets only
├── tailwind.config.js # Tailwind configuration
├── wrangler.toml # Cloudflare Pages config + mail vars
├── .assetsignore # Keeps repo-only files out of the deploy
├── package.json # Build scripts
├── sitemap.xml # XML sitemap with image tags
└── robots.txt # Search engine config
This is a static, SEO-first site. Highlights of the latest audit-driven refresh:
- Crawlable navigation: the navbar and footer are inlined into every HTML
page (no client-side
fetch()), so internal links are present in the HTML source that crawlers see and there is no layout shift while they load. - Valid structured data: every page ships a valid
@graphof Organization → LocalBusiness → WebSite → BreadcrumbList (Article/BlogPosting on blog posts, FAQPage on the home page). Product offers are expressed as anOfferCatalogso no fabricated prices are ever published. - Image SEO: all images are self-hosted, WebP (logos/photos) or AVIF, carry
descriptive filenames and
alttext, and havewidth/heightto remove layout shift. A dedicated 1200×630og-image.jpgis used for social previews. - Performance: Google Fonts (Google Sans) are self-hosted from
/assets/fonts/and preloaded; the Font Awesome kit is loaded withdefer. - Local SEO: NAP (name/address/phone) is consistent across the footer, JSON-LD, maps embed, and hCard; the LocalBusiness geo coordinates match the Google Maps pin.
- Content: a
Blogsection targets long-tail Kigali/B2B queries such as "chicken supplier Kigali", "whole chicken vs cuts", and "chicken cold chain", and the nine chicken meat pages under Chicken meat SEO pages above target "chicken cuts", "chicken meat delivery Kigali", "how to cook chicken" and "chicken nutrition per cut". - Sitemap-only discoverability: the nine pages are deliberately kept out of
the navbar. They are discoverable via
sitemap.xml, contextual links on the homepage and blog, and the cross-link grid at the foot of each page. - No fabricated claims: no prices are published, and certification language is deliberately held to what the homepage states — a documented HACCP-based plan and RSB registration, with formal HACCP certification still in progress. Keep the two in step if either changes.
- Node.js 18+
# Install dependencies
npm install
# Build CSS
npm run build:css
# Watch for changes (automatic rebuild)
npm run watch:cssOpen index.html in your browser, or serve locally:
# Using Python
python -m http.server 8000
# Using Node.js
npx servenpm run buildThis generates a minified css/tailwind.css from the HTML content sources. Always rebuild before deploying.
Cloudflare Pages serves both the static files and the functions/ directory, and
wrangler.toml points pages_build_output_dir at the repository root.
npm run build # rebuild Tailwind first
npx wrangler pages deploy . --project-name kacy.assetsignore keeps repo-only paths out of the upload — most importantly
.kilo/, which holds a stale worktree copy of the site that would otherwise be
published as a second, outdated version still containing the removed Formspree
form.
pages_build_output_dir = "."means the whole repository is the site root. If you add a directory that should not be public, add it to.assetsignore.
- Structured Data: Organization, WebSite, LocalBusiness, WebPage,
OfferCatalog, FAQPage, BreadcrumbList, plus ItemList / Service / HowTo on the
chicken meat pages and Article/BlogPosting on blog posts — all valid
@graph. - Open Graph + Twitter Cards:
og-image.jpg(1200×630) preview tags with dimensions and alt text on every page. - Sitemap: XML with image tags, submitted via robots.txt.
- Local SEO: Consistent NAP across footer, JSON-LD, and hCard; geo coords match the Google Maps pin.
- Canonical URLs: Trailing-slash canonicals on every page; no
hreflang(single-language site). - Titles and descriptions: kept at or under 60 and 158 characters respectively, matching the existing pages, so nothing is truncated in results.
- Content:
/blog/targets long-tail Kigali/B2B queries, and the nine chicken meat pages target cut, delivery, cooking, nutrition and safety searches. - FAQ integrity: every
FAQPageanswer matches the visible accordion text on the same page. If you edit one, edit both.
All website copy is written in plain, conversational language. No jargon, no corporate speak. The tone is direct and human — like talking to a real person who can help.
- HTML5: Semantic markup, inlined navbar/footer for crawlability
- Tailwind CSS v3: Pre-built via CLI (not CDN)
- Vanilla JavaScript: ES6 modules (mobile menu and contact form; no content fetching)
- Cloudflare Pages Functions:
POST /api/contact, with Resend for delivery - Font Awesome: Icons via deferred kit script (CDN)
- Fonts: Google Sans (self-hosted latin-subset WOFF2 in
/assets/fonts/) - Analytics: Google Analytics 4 (gtag, async)
The navbar and footer are inlined into every HTML page rather than loaded via JavaScript. When you update
components/navbar.htmlorcomponents/footer.html, apply the same change in every page's nav/footer block. There is no JS component loader, so static edits are instantly live.When editing a chicken meat page, remember three places must agree: the visible copy, the JSON-LD
@graph, and the cross-link grid at the foot of the page. A new page also needs asitemap.xmlentry.
- Logo: Replace
assets/images/kokolikooo-logo.webp. It is referenced in the navbar, footer, and JSON-LDlogo/og:imageof every page. - Hero image: Replace
assets/images/kacy-farms-hero.webpon the home page. - Delivery vehicle / facility photos: swap
delivery-truck-*.webp,processing-facility.webp,kacy-motel.webp,real-estate.webp. - Social links: update the social
<a>hrefs and thesameAsJSON-LD arrays (one source of truth:components/footer.html+ the Organization block on each page). - Fonts: the Google Sans WOFF2 is self-hosted in
assets/fonts/. Edit the@font-facerule incss/style.css, not a<link>to Google Fonts. - Contact Info: NAP lives in
components/footer.html,contact/index.html, and the LocalBusiness JSON-LD on every page — keep them in sync. - Certifications: the homepage shows RSB and HACCP as in progress. Do not describe either as held until that changes, on any page.
- After any HTML or Tailwind class change: run
npm run build:css(Tailwind is purged against the HTML content). Static copy edits (text, inline styles) need no build step.
- Phone: +250 788 309 077 | +250 788 867 296
- Email: info@kacy.rw
- Address: Cyanamo, Kabuga II, Rusororo, Gasabo District, Kigali, Rwanda
Copyright © 2026 KOKOLIKOOO by Kacy Farms. All rights reserved.