Have you ever solved a LeetCode problem, felt proud of your solution, and then... forgot to save it to GitHub? Or maybe you have dozens of solutions scattered across different files with no organization?
I got tired of manually copying my LeetCode solutions to GitHub after every "Accepted" verdict. So I built a Chrome extension that does it automatically. It's made my coding practice way more organized and saved me hours of tedious work.
The Problem
As developers grinding LeetCode, we face a few annoying challenges:
- Manual work is tedious: Copy code → Open GitHub → Create file → Paste → Commit → Push. Every. Single. Time.
- No organization: Files named randomly, no structure, difficult to find solutions later
- Multiple approaches: Solved the same problem differently? No easy way to compare solutions.
I wanted something that would just... work. Hit "Submit", get "Accepted", and solution automatically in GitHub with proper formatting and metadata.
The Solution: LeetCode GitHub Sync Extension
I built a Manifest V3 Chrome extension that:
- Detects when you get "Accepted" on LeetCode
- Extracts your solution code automatically
- Pushes it to your GitHub repository
- Organizes files by difficulty (Easy/Medium/Hard)
- Supports multiple solutions for the same problem (Solution A, B, C...)
- Includes rich metadata (problem URL, difficulty, timestamps)
And the best part? It has a floating ⚡ button as a reliable backup when auto-detection doesn't work.
Architecture & Tech Stack
Tech Stack
- Manifest V3 (Chrome's latest extension standard)
- GitHub REST API (for file creation/updates)
- Monaco Editor interaction (for code extraction)
- Chrome Storage API (for settings persistence)
- Vanilla JavaScript (no frameworks needed!)
Key Components
leetcode-github-sync/
├── manifest.json # Extension config (Manifest V3)
├── content.js # Page interaction & detection
├── background.js # GitHub API integration
├── popup.html/js # Settings UI
└── debug-helper.js # Diagnostic tool
How It Works
1. Detection System
The extension watches for when you get "Accepted" on LeetCode using multiple methods. Since LeetCode updates their UI frequently, I built in several fallback approaches:
- DOM Mutation Observer - Watches for new elements being added to the page
- CSS Class Selectors - Looks for success/green/accepted classes
- Periodic Checking - Checks every 3 seconds as a backup
- Text Content Scanning - Searches for "Accepted" text
If auto-detection fails, there's always the ⚡ floating button you can click manually.
2. Code Extraction
LeetCode uses Monaco Editor (the same one VS Code uses). Getting code out of it requires trying multiple approaches since the editor's internal structure can vary:
- Try the Monaco API methods (
getEditors(),getModels()) - Extract from DOM elements (
.view-lineclasses) - Use alternative Monaco model APIs
- Fall back to manual sync button if all else fails
The extension tries each method in sequence until one works.
3. GitHub Integration
The background script handles all communication with GitHub's API. When you get "Accepted", the content script sends a message to the background script with your code, problem details, and language. The background script then:
- Checks if the file already exists
- Decides whether to create a new file or append to existing
- Formats your solution with metadata
- Pushes to GitHub using their REST API
4. Multiple Solutions Support
When you solve the same problem again, the extension detects existing solution markers in your file and automatically assigns the next letter (B, C, D, etc.). It can optionally ask for your approval before appending, so you stay in control.
File Structure Example
Your solutions get organized beautifully:
leetcode-solutions/
├── easy/
│ └── 9-palindrome-number.py
├── medium/
│ └── 2-add-two-numbers.cpp
└── hard/
└── 4-median-of-two-sorted-arrays.py
Each file contains rich metadata:
# 9. Palindrome Number
# Difficulty: Easy
# URL: https://leetcode.com/problems/palindrome-number/
# Date: 2/10/2026
# ========== Solution A ==========
# Language: python3
# Date: 2/10/2026
class Solution:
def isPalindrome(self, x: int) -> bool:
if x < 0:
return False
return str(x) == str(x)[::-1]
# ========== Solution B ==========
# Language: python3
# Date: 2/11/2026
class Solution:
def isPalindrome(self, x: int) -> bool:
if x < 0 or (x % 10 == 0 and x != 0):
return False
reversed_half = 0
while x > reversed_half:
reversed_half = reversed_half * 10 + x % 10
x //= 10
return x == reversed_half or x == reversed_half // 10
Challenges & Solutions
Challenge 1: LeetCode UI Changes Frequently
Problem: Selectors break when LeetCode updates their UI
Solution: Multiple detection methods acting as fallbacks. The ⚡ floating button provides a reliable manual sync option that always works. Instead of relying on one way to detect "Accepted", the extension tries several different approaches.
Challenge 2: Code Extraction Reliability
Problem: Monaco Editor API isn't always accessible
Solution: 5 different extraction methods, tried in sequence:
monaco.editor.getEditors()monaco.editor.getModels()- DOM extraction from
.view-lineelements - Alternative Monaco model APIs
- Manual sync button as ultimate fallback
Challenge 3: Manifest V3 Restrictions
Problem: Content scripts can't access Chrome storage directly
Solution: The extension uses message passing between the content script (running on LeetCode pages) and the background service worker (handling GitHub operations). The content script collects data, sends it to the background script, and the background script handles all the API calls.
Challenge 4: Handling Special Characters
Problem: Unicode characters in code weren't uploading correctly to GitHub
Solution: Proper Base64 encoding with UTF-8 support ensures that code with special characters, emojis, or non-ASCII text gets uploaded correctly.
What I Learned
Technical Insights
- Manifest V3 is strict but better - Service workers are more efficient than background pages
- Multiple fallback strategies are essential - When dealing with dynamic UIs like LeetCode
- User-controlled actions > Pure automation - The ⚡ button gets used more than I expected
- GitHub API is straightforward - The REST API is well-documented and reliable
- Monaco Editor is powerful - But accessing it requires understanding its internal structure
Product Insights
- Manual fallback is crucial - Auto-detection fails ~20% of the time due to UI changes
- Users want control - Approval dialog for multiple solutions is heavily used
- Visual feedback matters - Notifications and loading states reduce user anxiety
- Organization is key - Difficulty-based folders are the most popular option
- Documentation is critical - Included debug-helper.js and multiple .md files for troubleshooting
Reflections
Building this extension taught me that reliability beats perfection. I initially wanted 100% automatic detection, but realized that a manual fallback (the ⚡ button) provides a better user experience than a flaky auto-detection system.
The extension has saved me countless hours of manual work and made my LeetCode practice more organized. Sharing my solutions with recruiters is now as simple as sending a GitHub link.
🔗 Resources
- GitHub Repository: [[https://github.com/Likhit-Kumar/Leetcode-Github-Sync]]
- Chrome Web Store: [Coming soon]
💭 Final Thoughts
If you're grinding LeetCode, this extension can save you hours of manual work and keep your solutions organized forever. The combination of automatic syncing + reliable manual fallback has made it an essential part of my coding practice.
For the LeetCode community: Feel free to fork, contribute, or suggest features!
Tags: #leetcode #github #chrome-extension #automation #productivity #javascript #webdev #coding
Questions or issues? Drop a comment below!
Top comments (0)