<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: gitau254-m</title>
    <description>The latest articles on Forem by gitau254-m (@gitau254m).</description>
    <link>https://forem.com/gitau254m</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3812862%2F3bdc3211-cdb7-46a9-9dbc-4664fb256926.png</url>
      <title>Forem: gitau254-m</title>
      <link>https://forem.com/gitau254m</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/gitau254m"/>
    <language>en</language>
    <item>
      <title>How I Built a Free KCSE Course Checker for Kenyan Students Using React, Supabase and M-Pesa</title>
      <dc:creator>gitau254-m</dc:creator>
      <pubDate>Sun, 08 Mar 2026 12:12:44 +0000</pubDate>
      <link>https://forem.com/gitau254m/how-i-built-a-free-kcse-course-checker-for-kenyan-students-using-react-supabase-and-m-pesa-23aa</link>
      <guid>https://forem.com/gitau254m/how-i-built-a-free-kcse-course-checker-for-kenyan-students-using-react-supabase-and-m-pesa-23aa</guid>
      <description>&lt;h1&gt;
  
  
  How I Built a Free KCSE Course Checker for Kenyan Students Using React, Supabase and M-Pesa
&lt;/h1&gt;

&lt;p&gt;Every year, thousands of Kenyan Form 4 leavers wait anxiously for KUCCPS placement — not knowing which university courses they actually qualify for. I built a tool to solve that.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Try it here:&lt;/strong&gt; &lt;a href="https://course-compass-guide.vercel.app" rel="noopener noreferrer"&gt;course-compass-guide.vercel.app&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;After KCSE results are released, students struggle with two things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;They don't know how to calculate their &lt;strong&gt;cluster scores&lt;/strong&gt; — the scores KUCCPS uses to determine eligibility for specific courses&lt;/li&gt;
&lt;li&gt;Even if they know their grades, they have no easy way to see which of the &lt;strong&gt;393 degree and diploma courses&lt;/strong&gt; they qualify for&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The official KUCCPS website shows cutoff points but doesn't help students check their own eligibility automatically.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;KCSE Course Checker&lt;/strong&gt; — a web app where a student enters their KCSE subject grades and instantly sees:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Their calculated cluster scores for all 6 KUCCPS clusters&lt;/li&gt;
&lt;li&gt;Every &lt;strong&gt;degree programme&lt;/strong&gt; they qualify for (based on 2024 KUCCPS cutoff points)&lt;/li&gt;
&lt;li&gt;Every &lt;strong&gt;diploma programme&lt;/strong&gt; they qualify for&lt;/li&gt;
&lt;li&gt;Courses filtered by their interest areas (Engineering, Medicine, Business, Law, etc.)&lt;/li&gt;
&lt;li&gt;The official 2024 KUCCPS cutoff points PDF for verification&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Tech Stack
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Technology&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Frontend&lt;/td&gt;
&lt;td&gt;React 18 + TypeScript&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Styling&lt;/td&gt;
&lt;td&gt;Tailwind CSS + shadcn/ui&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Database&lt;/td&gt;
&lt;td&gt;Supabase (PostgreSQL)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Auth&lt;/td&gt;
&lt;td&gt;Supabase Google OAuth&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Payments&lt;/td&gt;
&lt;td&gt;IntaSend M-Pesa STK Push&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Serverless&lt;/td&gt;
&lt;td&gt;Supabase Edge Functions (Deno)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PWA&lt;/td&gt;
&lt;td&gt;vite-plugin-pwa&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hosting&lt;/td&gt;
&lt;td&gt;Vercel&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  The Cluster Score Formula
&lt;/h2&gt;

&lt;p&gt;KUCCPS uses a cluster scoring system. Each university course belongs to one of 6 clusters, and each cluster uses specific KCSE subjects.&lt;/p&gt;

&lt;p&gt;After studying the 2024 placement data, I calibrated this formula:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;C = √((r/48) × (t/84)) × 48 × 0.957
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;r&lt;/code&gt; = raw cluster subject score (max 48 points across 4 subjects)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;t&lt;/code&gt; = KCSE aggregate score (max 84 points across 7 subjects)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;0.957&lt;/code&gt; = calibration factor matched to actual 2024 KUCCPS placements&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This produces cluster scores that match real 2024 KUCCPS placement data closely enough to give students accurate guidance.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Payment Flow (Secure M-Pesa Integration)
&lt;/h2&gt;

&lt;p&gt;One challenge was building a secure payment system. Here's how it works:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. User enters phone number
2. Frontend calls intasend-stk Edge Function
3. Edge Function sends STK Push via IntaSend API
4. IntaSend prompts user's phone with M-Pesa PIN request
5. User enters PIN on their phone
6. IntaSend calls our mpesa-callback Edge Function (webhook)
7. Edge Function verifies transaction and updates payments table to 'confirmed'
8. Frontend polls the payments table every 3 seconds
9. When status = 'confirmed', results are unlocked
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The key security principle: &lt;strong&gt;the frontend never grants itself access&lt;/strong&gt;. It only reads what the database says. The database is only updated by the server-side Edge Function after IntaSend's webhook confirms the payment. This means even if a user tried to skip the payment, they'd still be blocked.&lt;/p&gt;




&lt;h2&gt;
  
  
  Database Structure
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;users&lt;/span&gt;              &lt;span class="c1"&gt;-- student profiles&lt;/span&gt;
&lt;span class="n"&gt;user_results&lt;/span&gt;       &lt;span class="c1"&gt;-- KCSE subject grades&lt;/span&gt;
&lt;span class="n"&gt;user_cluster_results&lt;/span&gt; &lt;span class="c1"&gt;-- calculated cluster scores  &lt;/span&gt;
&lt;span class="n"&gt;payments&lt;/span&gt;           &lt;span class="c1"&gt;-- M-Pesa payment records&lt;/span&gt;
&lt;span class="n"&gt;courses&lt;/span&gt;            &lt;span class="c1"&gt;-- 393 courses with cutoff points&lt;/span&gt;
&lt;span class="n"&gt;degree_programme_cutoffs_exact_2024&lt;/span&gt; &lt;span class="c1"&gt;-- 703 exact 2024 KUCCPS cutoffs&lt;/span&gt;
&lt;span class="n"&gt;reviews&lt;/span&gt;            &lt;span class="c1"&gt;-- student reviews (admin approved)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All tables have Row Level Security (RLS) enabled so users can only access their own data.&lt;/p&gt;




&lt;h2&gt;
  
  
  Key Features
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Returning user flow&lt;/strong&gt; — students who paid before can retrieve their results by name and phone number without paying again. Google OAuth users get this automatically.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Diploma-only mode&lt;/strong&gt; — if a student's aggregate is below C+ (46/84 points), the app automatically switches to diploma-only mode, hides degree results, and shows an explanation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Interest filtering&lt;/strong&gt; — students can filter results by field of interest so they don't scroll through 291 degrees looking for relevant courses.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PWA&lt;/strong&gt; — the app is installable on Android and iPhone without going through the Play Store or App Store.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I Learned
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. IntaSend + Supabase Edge Functions work great together for M-Pesa&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There's very little documentation on building M-Pesa integrations with modern JavaScript frameworks in Kenya. IntaSend abstracts the Safaricom Daraja API well and their STK Push is straightforward once you understand the webhook flow.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. React SPAs need extra work for Google indexing&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Since all the content is loaded via JavaScript, Google struggles to read it. I had to add structured data (JSON-LD), proper meta tags, a sitemap, and submit to Google Search Console manually.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Calibrating the cluster formula took the most time&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I spent hours comparing my formula output against known 2024 KUCCPS placements to get the calibration factor right. The official formula isn't published anywhere publicly.&lt;/p&gt;




&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Custom &lt;code&gt;.co.ke&lt;/code&gt; domain when the app gets more users&lt;/li&gt;
&lt;li&gt;Admin dashboard to view payments and user stats&lt;/li&gt;
&lt;li&gt;Push notifications for KUCCPS placement results&lt;/li&gt;
&lt;li&gt;More courses including TVET programmes&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Try It
&lt;/h2&gt;

&lt;p&gt;👉 &lt;strong&gt;Live app:&lt;/strong&gt; &lt;a href="https://course-compass-guide.vercel.app" rel="noopener noreferrer"&gt;course-compass-guide.vercel.app&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;👨‍💻 &lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/gitau254-m/course-compass" rel="noopener noreferrer"&gt;github.com/gitau254-m/course-compass&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you know any Kenyan Form 4 leavers or their parents — please share this with them. And if you're a developer interested in Kenyan EdTech or M-Pesa integrations, feel free to explore the code.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Built by Wallace Gitau — Front-End Developer based in Kenya. Open to internships and freelance work.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Tags: kenya, react, supabase, mpesa, edtech, webdev, typescript, pwa&lt;/em&gt;&lt;/p&gt;

</description>
      <category>kenya</category>
      <category>webdev</category>
      <category>react</category>
      <category>supabase</category>
    </item>
  </channel>
</rss>
