DEV Community

YMori
YMori

Posted on

Kaggle Code Competitions : GitHub Actions + Kaggle API Cloud Workflow

The Problem

The goal: edit a notebook anywhere, push to GitHub, and have it appear on Kaggle ready to submit.

The Workflow

Edit notebook → git push → GitHub Actions → kaggle kernels push → Submit via browser
Enter fullscreen mode Exit fullscreen mode
Step Automated? How
Edit notebook - Any device
Upload to Kaggle Yes GitHub Actions + kaggle kernels push
Submit Manual Browser: "Submit to Competition"
Check score Yes kaggle competitions submissions API

Why Can't We Fully Automate?

I spent a lot of time trying to make submission fully automatic. Here's what I found:

The Kaggle API's CreateCodeSubmission endpoint returns 403 Forbidden:

Permission 'kernelSessions.get' was denied
Enter fullscreen mode Exit fullscreen mode

I tested every combination:

Auth Method CLI Version API Result
Legacy API Key 1.8.4 competition_submit_code 403
New API Token (KGAT_...) 1.8.4 competition_submit_code 403
New API Token (KGAT_...) 2.0.0 competition_submit_code 403
New API Token (KGAT_...) 2.0.0 competitions submit (file) 400

Why?

  • Permission scope limitation: kernelSessions.get monitors notebook execution sessions. Public API tokens don't include this scope.
  • Code competitions are special: Unlike uploading a CSV, notebook submission involves re-execution and progress monitoring on the platform, requiring higher-level control permissions.
  • File submission doesn't work either: Code competitions reject direct CSV uploads (400 Bad Request).

Conclusion: Until the API is updated, the hybrid approach (automate deployment, manually submit) is the most practical.

Setup

Directory Structure

kaggle-competitions/
├── .github/workflows/
│   └── kaggle-push.yml
├── deep-past/
│   ├── kernel-metadata.json
│   └── deep-past-baseline.ipynb
Enter fullscreen mode Exit fullscreen mode

kernel-metadata.json

{
  "id": "your-username/your-kernel-slug",
  "title": "Your Kernel Title",
  "code_file": "your-notebook.ipynb",
  "language": "python",
  "kernel_type": "notebook",
  "is_private": "false",
  "enable_gpu": "false",
  "enable_internet": "false",
  "competition_sources": ["competition-slug"]
}
Enter fullscreen mode Exit fullscreen mode

Critical: enable_internet must be "false". Internet ON prevents the notebook from being eligible for submission in code competitions.

GitHub Actions Workflow

name: Kaggle Kernels Push

on:
  workflow_dispatch:
    inputs:
      notebook_dir:
        description: 'Notebook directory'
        required: true
        type: string

jobs:
  push:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: '3.12'

      - name: Install kaggle CLI
        run: pip install kaggle

      - name: Push notebook to Kaggle
        env:
          KAGGLE_API_TOKEN: ${{ secrets.KAGGLE_API_TOKEN }}
        run: kaggle kernels push -p "${{ inputs.notebook_dir }}"
Enter fullscreen mode Exit fullscreen mode

Set KAGGLE_API_TOKEN in your repo's GitHub Secrets (Kaggle Settings → API Tokens → Generate).

Gotchas

1. Data Path

competition_sources mounts at:

/kaggle/input/competitions/<slug>/
Enter fullscreen mode Exit fullscreen mode

NOT /kaggle/input/<slug>/. The competitions/ subdirectory is easy to miss.

2. Windows Encoding

kaggle kernels output crashes on Windows with non-ASCII characters (cp932 error). Use the API directly with urllib.request and UTF-8 decoding instead.

3. Kernel Slug Must Match Title

If your kernel-metadata.json title doesn't resolve to the specified id slug, you'll get a 400 error on push. Keep them consistent.

Results

I used this workflow for the Deep Past Challenge (Akkadian → English translation):

  • Pushed a TF-IDF nearest neighbor baseline via GitHub Actions
  • Submitted via browser
  • Public Score: 5.6

The iteration cycle is fast: edit locally → push → submit → check score.

Summary

Full automation of Kaggle code competition submissions isn't possible via the public API (as of Feb 2026). But automating everything up to the submit button still saves a lot of time and lets you work from any device.

The one manual click is a small price to pay.

Top comments (0)