Convert Jupyter Notebooks to Markdown for LLMs
If you are trying to feed a Jupyter Notebook into an LLM and getting hallucinated code or ignored outputs, the problem is the raw JSON structure of the .ipynb file.
The Quick Answer
- Run the notebook and save it, so the outputs are stored in the
.ipynbfile. - Upload the
.ipynbfile to the Jupyter Notebook to Markdown converter. - Paste or upload the Markdown into Claude, ChatGPT, NotebookLM or your RAG pipeline.
You get your markdown cells, your code and the saved outputs in order: printed text, error tracebacks, and pandas DataFrames as real Markdown tables.
Why Raw .ipynb Files Waste Tokens
A typical Jupyter cell looks like this under the hood:
{
"cell_type": "code",
"execution_count": 42,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Accuracy: 0.95\n"
]
}
],
"source": [
"print(f'Accuracy: {accuracy}')"
]
}
An LLM has to read all of that just to see print(f'Accuracy: {accuracy}') and its output. Charts make it worse: plots are stored inside the file as long base64 strings that can fill a context window on their own.
What the Converted Notebook Looks Like
Here is a small notebook with a DataFrame, a plot and an error, after conversion:
# Sales analysis
Quick look at **scores**.
```python
import pandas as pd
df = pd.DataFrame({'name': ['Ana', 'Bo'], 'score': [91, 78]})
print('Accuracy: 0.95')
df.head()
```
Output:
```
Accuracy: 0.95
```
| | name | score |
| --- | --- | --- |
| 0 | Ana | 91 |
| 1 | Bo | 78 |
```python
df.plot()
```
Output:
_[image output omitted]_
```python
df['missing']
```
Output:
```
KeyError: 'missing'
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
Cell In[3], line 1
----> 1 df['missing']
KeyError: 'missing'
```
What to expect:
- Markdown cells come through as written, so headings, lists and bold text stay intact. Images pasted into a markdown cell are the exception: the file stores them as base64 text, so they are replaced by their alt text (or an
[embedded image omitted]note). Links to images, includingattachment:links, are kept. - Code cells become code blocks labelled with the notebook's language (
python,r,juliaand so on). Empty code cells are skipped. - Printed output and errors appear as text blocks under an
Output:line below the code that produced them. Terminal colour codes are removed from tracebacks. - DataFrames become Markdown tables, which LLMs read more reliably than HTML.
- Long outputs are cut: any single output over 60 lines or 6,000 characters keeps its beginning and ends with a note saying how many lines were left out.
- Charts and images are not included. You get the image's text label if the notebook saved one (matplotlib saves something like
<Figure size 640x480 with 1 Axes>), otherwise an[image output omitted]note, never the base64 data. If a chart matters, describe it in a markdown cell or analyse the image separately with a multimodal model. - Widgets and JavaScript outputs are skipped.
A notebook with no cells, or only empty ones, is rejected with an error rather than giving you a blank result. Old v3 notebooks are not supported. Open them in Jupyter and save them again, which writes the current format, then upload. If you are converting from GitHub, download the file with the Raw button: the normal GitHub page for a notebook is HTML, not the notebook itself.
Why Not Jupyter's Own Markdown Export?
jupyter nbconvert --to markdown is fine for code and printed output, but it leaves DataFrames as raw HTML tables with inline CSS, and it saves plots as separate image files next to the .md. For feeding an LLM, Markdown tables and no image files are easier to work with.
Ingesting into Your Pipeline
Once you have the Markdown, you can use it directly in NotebookLM, Claude Projects or a custom RAG application. Because the structure is standard Markdown, you can apply semantic chunking, as covered in our guide on chunking Markdown for vector databases. For standalone datasets, the CSV to Markdown converter turns a CSV straight into a table.
Frequently Asked Questions
Q: Can I upload an .ipynb file to file2markdown directly? A: Yes. Upload it on the Jupyter Notebook to Markdown page.
Q: Why shouldn't I just upload the .ipynb file to ChatGPT?
A: Some tools can read .ipynb files, but the JSON metadata and base64 images cost tokens and can confuse the model. Markdown gives it the same content in far less space.
Q: Are my code outputs preserved? A: Yes, as long as you save the notebook after running it. Printed output, results and error tracebacks appear under the code that produced them. Very long outputs are cut after 60 lines or 6,000 characters.
Q: Can I convert many notebooks at once? A: Yes. Put them in a ZIP and upload that, or select several files: Pro converts 10 files at a time in the web app, and a Pro API key removes the daily limit on our MCP server if you'd rather have your AI assistant do the converting.
The Markdown Memo
A fortnightly note for lawyers, researchers, accountants, and anyone else drowning in PDFs, scans, and decks. No spam.