Live Chat

We'll need to share your messages (and your email address if you're logged in) with our live chat provider, Drift. Here's their privacy policy.

If you don't want to do this, you can email us instead at

Turning a Jupyter notebook into a web app
« Anvil Tutorials
Putting a web front-end on a Jupyter notebook
5m 28s

Let’s say you’re a data scientist, and you’ve been asked to solve a problem. Of course, what you really want is to build an interactive tool, so your colleagues can solve the problem themselves!

In this tutorial, we take a machine-learning model in a Jupyter notebook, and turn it into a web application using the Anvil Uplink (written version below):

The video in writing

Prefer reading to watching? Here’s a written version.

First we discuss the principles we will be using, before building the app itself.

How the connection is made | 0:21 - 0:45

We use the Anvil Uplink to connect a Jupyter Notebook to Anvil. It’s a library you can pip install on your computer or wherever your Notebook is running.

It allows you to:

It works for any Python process - this happens to be a Jupyter Notebook, but it could be an ordinary Python script, a Flask app, even the Python REPL!

Running on-site | 0:45 - 1:02

Doing this 100% on-site in your own private network is supported. You get your own private version of the Anvil server (it’s three Docker containers) and the system runs as before, but all within your network.

Read this article for more information.

Plan of action | 1:02 - 1:10

We’re going to:

  1. Set up a Jupyter Notebook
  2. Connect it to an Anvil app
  3. Build a user interface to our model

Setting up the Jupyter Notebook | 1:10 - 1:22

We start with a pre-existing Jupyter Notebook containing a classification model that distinguishes between cats and dogs. You give it an image and it scores it as ‘cat’ or ‘dog’.

Our thanks to Uysim Ty for sharing it on Kaggle.

Making the connection | 1:22 - 1:54

We enable the Anvil Uplink and connect the notebook.

First, we enable the Uplink in the Anvil IDE.

A modal from the IDE showing a randomised key you can use to connect to your Anvil app from any Python process.

Then we pip install the Uplink library on the machine the Jupyter Notebook is running on:

pip install anvil-uplink

By adding the following lines, we connect the Jupyter Notebook to our Anvil app:

import anvil.server


Now our Jupyter Notebook can do anything we can do in an Anvil Server Module - call Anvil server functions, store data in Data Tables, and define server functions to be called from other parts of the app.

Loading an image into the Notebook | 1:54 - 3:14

We load the image into the Jupyter Notebook by making an anvil.server.callable function in the Jupyter Notebook:


def classify_image(file):
    with as filename:
        img = load_img(filename)

This function can be called from the client-side code (and server-side code) of our Anvil app.

We’re passing the image in as an Anvil Media object, which we then write to a temporary file.

The load_img function loads the file into Pillow, a Python imaging library.

Then we can do a bit of post-processing of the image to get it into a format that the model likes:

    # Inside the classify_image function

    img = img.resize((128, 128), resample=PIL.Image.BICUBIC)
    arr = img_to_array(img)
    arr = np.expand_dims(arr, axis=0)
    arr /= 255

Then we can just pass it into our model and return the result:

    # Inside the classify_image function

    score = model.predict(arr)
    return ('dog' if score < 0.5 else 'cat', float(score))

Building a User Interface | 3:14 - 3:45

We drag-and-drop components to create a User Interface. It consists of a FileLoader to upload the images, an Image to display them, and a Label to display the classification.

The Anvil Editor design view showing the app with some components dropped into it.

Making the User Interface call the Jupyter Notebook | 3:45 - 4:32

Now to write some Python code that runs in the browser so the app responds when an image is loaded in.

We define an event handler that triggers when the FileLoader gets a new file:

  def file_loader_1_change(self, file, **event_args):
    """This method is called when a new file is loaded into this FileLoader."""
    result, score ='classify_image', file)
    self.result_lbl.text = "%s (%0.2f)" % (result, score)
    self.image_1.source = file

The first line calls the classify_image function in the Jupyter Notebook, passing in the image file.

Then we display the result (cat or dog) and the score (0 to 1; completely dog or completely cat).

We also put the image file into the Image component so that the user can see their cat or dog (or other cat-or-dog-like image) and decide if they agree with the result.

It works! Now to publish it | 4:32 - 5:10

We give it a quick test by uploading an image of a cat - yes, it works, that’s a cat.

An app containing an Upload Photo button, an image of a cat, and the text 'cat (0.96)'

It’s already published at a private URL. By click a button and entering our chosen domain name, we made it public at

Try it for yourself

Build this app for yourself - Sign up and follow along, or watch more tutorials in the Anvil Learning Centre.

The Jupyter Notebook is available on Kaggle - our thanks to Uysim Ty, its creator.

Next up

If you’d like to learn the essentials of Anvil, start with the Hello, World! tutorial.

If you’d like to learn more about the Uplink, you can read the reference docs.