# Leetcode Add To List

> Add problems to a LeetCode problem list (favorites list) via the GraphQL API using playwright-cli. Use when the user wants to add LeetCode problems to a custom list, populate a LeetCode problem list, sync problems from AlgoMonster or Blind 75 or any curated list to LeetCode, or bulk-add questions to a LeetCode favorite list. Trigger phrases include "add to leetcode list", "add problems to leetcode", "populate leetcode list", "sync to leetcode", "add to my leetcode list", "leetcode problem list".

- Skill: `g-kartik/leetcode-add-to-list` (Agent Skill)
- Install (CLI): `npx skillmds@latest add g-kartik/leetcode-add-to-list`
- Raw SKILL.md: https://api.skillmd.com/api/skills/g-kartik/leetcode-add-to-list/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Integrations & APIs
- Author: g-kartik (https://skillmd.com/u/g-kartik)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/g-kartik/leetcode-add-to-list

---


# Add Problems to LeetCode List

Uses the LeetCode GraphQL API (`addQuestionToFavorite` mutation) via a browser session to bulk-add problems to a custom LeetCode problem list.

## How LeetCode Lists Work

- Each custom list has a **hash** (e.g. `dyf6r5b7`) visible in its URL: `https://leetcode.com/problem-list/<hash>/`
- Problems are identified by their **numeric ID** (the number in the problem URL, e.g. `1` for Two Sum)
- The API uses the session cookies (especially `csrftoken`) from the logged-in browser — no separate auth needed

## Prerequisites

- A browser session attached via playwright-cli CDP (usually port 9222)
- User must be logged into LeetCode in that browser
- The target problem list hash (from the URL)

## Steps

### 1. Attach to the browser

```bash
playwright-cli attach --cdp=http://localhost:9222
```

### 2. Navigate to the target list page (establishes cookies)

```bash
playwright-cli goto https://leetcode.com/problem-list/<LIST_HASH>/
```

### 3. Add problems via GraphQL

Use `playwright-cli run-code --filename=<script>` with a script that calls `page.evaluate`:

```js
async page => {
  const results = await page.evaluate(async () => {
    const problems = [
      {id: '1',   name: 'Two Sum'},
      {id: '217', name: 'Contains Duplicate'},
      // ... more problems
    ];

    const csrftoken = document.cookie.match(/csrftoken=([^;]+)/)?.[1] || '';
    const favoriteIdHash = 'dyf6r5b7'; // replace with actual list hash
    const results = [];
    const query = `mutation addQuestionToFavorite($favoriteIdHash: String!, $questionId: String!) {
      addQuestionToFavorite(favoriteIdHash: $favoriteIdHash, questionId: $questionId) {
        ok
        error
        questionId
        favoriteIdHash
      }
    }`;

    for (const p of problems) {
      const resp = await fetch('/graphql/', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'x-csrftoken': csrftoken,
          'Referer': `https://leetcode.com/problem-list/${favoriteIdHash}/`,
          'x-operation-name': 'addQuestionToFavorite',
        },
        body: JSON.stringify({
          operationName: 'addQuestionToFavorite',
          variables: { favoriteIdHash, questionId: p.id },
          query
        })
      });
      const data = await resp.json();
      results.push({
        name: p.name,
        id: p.id,
        ok: data?.data?.addQuestionToFavorite?.ok,
        error: data?.data?.addQuestionToFavorite?.error
      });
      await new Promise(r => setTimeout(r, 150)); // polite delay
    }
    return results;
  });
  return JSON.stringify(results, null, 2);
}
```

### 4. Verify

Reload the page and take a screenshot to confirm the question count.

## AlgoMonster 50 Problem IDs

For the AlgoMonster Monster 50 list (read from https://algo.monster/practice/monster50):

| # | Problem | LeetCode ID | Difficulty |
|---|---------|-------------|------------|
| 1 | Two Sum | 1 | Easy |
| 2 | Contains Duplicate | 217 | Easy |
| 3 | Best Time to Buy and Sell Stock | 121 | Easy |
| 4 | Valid Palindrome | 125 | Easy |
| 5 | Valid Parentheses | 20 | Easy |
| 6 | Binary Search | 704 | Easy |
| 7 | Reverse Linked List | 206 | Easy |
| 8 | Merge Two Sorted Lists | 21 | Easy |
| 9 | Linked List Cycle | 141 | Easy |
| 10 | Same Tree | 100 | Easy |
| 11 | Maximum Depth of Binary Tree | 104 | Easy |
| 12 | Invert Binary Tree | 226 | Easy |
| 13 | Climbing Stairs | 70 | Easy |
| 14 | Group Anagrams | 49 | Medium |
| 15 | Top K Frequent Elements | 347 | Medium |
| 16 | Longest Consecutive Sequence | 128 | Medium |
| 17 | Container With Most Water | 11 | Medium |
| 18 | 3Sum | 15 | Medium |
| 19 | Longest Substring Without Repeating Characters | 3 | Medium |
| 20 | Longest Repeating Character Replacement | 424 | Medium |
| 21 | Min Stack | 155 | Medium |
| 22 | Daily Temperatures | 739 | Medium |
| 23 | Find Minimum in Rotated Sorted Array | 153 | Medium |
| 24 | Search in Rotated Sorted Array | 33 | Medium |
| 25 | Remove Nth Node From End of List | 19 | Medium |
| 26 | Merge Intervals | 56 | Medium |
| 27 | Insert Interval | 57 | Medium |
| 28 | Non-overlapping Intervals | 435 | Medium |
| 29 | Binary Tree Level Order Traversal | 102 | Medium |
| 30 | Validate Binary Search Tree | 98 | Medium |
| 31 | Kth Smallest Element in a BST | 230 | Medium |
| 32 | Lowest Common Ancestor of a Binary Tree | 236 | Medium |
| 33 | Number of Islands | 200 | Medium |
| 34 | Clone Graph | 133 | Medium |
| 35 | Graph Valid Tree | 261 | Medium (Premium) |
| 36 | Course Schedule | 207 | Medium |
| 37 | Pacific Atlantic Water Flow | 417 | Medium |
| 38 | K Closest Points to Origin | 973 | Medium |
| 39 | Combination Sum | 39 | Medium |
| 40 | Word Search | 79 | Medium |
| 41 | House Robber | 198 | Medium |
| 42 | Coin Change | 322 | Medium |
| 43 | Word Break | 139 | Medium |
| 44 | Longest Increasing Subsequence | 300 | Medium |
| 45 | Trapping Rain Water | 42 | Hard |
| 46 | Minimum Window Substring | 76 | Hard |
| 47 | Word Ladder | 127 | Hard |
| 48 | Merge K Sorted Lists | 23 | Hard |
| 49 | Find Median from Data Stream | 295 | Hard |
| 50 | N-Queens | 51 | Hard |

## Notes

- The mutation is idempotent — adding a problem that's already in the list returns `ok: true` without duplicating it
- `questionId` is a string, not an integer — pass the problem number as a string
- **Graph Valid Tree (#261)** is LeetCode Premium and may not appear in the public list count even though the API returns `ok: true`
- The browser automatically sends session cookies (auth) — no manual cookie handling needed
- The `csrftoken` cookie value must also be set as the `x-csrftoken` **header** — this is Django's double-submit CSRF protection (cookie alone isn't enough, header must match cookie)
- All fetch calls must be made via `page.evaluate()` so they run inside the browser context (same-origin, so cookies are sent automatically)

