Button guide
A page where colleagues upload a file, your script processes it, and they download the result setup in minutes, free for 3 people
You can give a file-processing script its own upload and download page with Button (https://button.bitgate.dev) without writing a web server. The script runs on your computer, accepts up to 8 files at a time (up to 25 MB each and 100 MB total per run), and sends the output files back to your colleague's browser. It is $0 for 1 published tool, 3 people, and 100 runs per month, or $15/month for Pro.
What the upload, process, download pattern involves
When you have a script that takes a CSV, an Excel workbook, a PDF, or a batch of images and turns it into something else, wrapping it in a web page sounds like a tiny job. If you build it yourself with Flask or FastAPI, you end up writing and maintaining several extra pieces around the script:
- routes and an HTML form for the inputs,
- upload handling and temporary storage so two people don't overwrite each other's files,
- a cleanup job to delete old uploads and outputs,
- a login system so only the right colleagues can use it,
- a background job queue so a slow run doesn't time out the HTTP request,
- somewhere to host the app with HTTPS.
You can also use Streamlit and put st.file_uploader and st.download_button around your code. streamlit run app.py serves it on your local network with no login by default; st.login() adds sign-in through an OpenID Connect provider, but you still write the email allowlist check yourself. Streamlit Community Cloud hosts one private app for free, with invited viewers, and the app sleeps after 12 hours without traffic until the next visit wakes it.
With Button, you skip the web code. You keep your script in Python, Node, R, PowerShell, bash, or a compiled binary, and it runs on your own computer. Button gives it a web form, handles the sign-in (Google or a one-time email code), relays the form values and files between the browser and your computer, and holds the output files for your colleague to download.
Button's limits and pricing
Because jobs run on your computer and files pass through Button's servers on the way in and out, there are hard limits you should check against your workload before you start.
| Item | Free ($0) | Pro ($15/month or $144/year at $12/month) |
|---|---|---|
| Published tools | 1 | 50 |
| People (invited colleagues; you don't count) | 3 | 250 |
| Runs per month (includes your own runs) | 100 | 5,000 |
| File transfer per month | 1 GB | 50 GB |
| Max size per file | 25 MB | 25 MB |
| Max files and total size per run | 8 files, 100 MB | 8 files, 100 MB |
| Max run duration | 30 minutes | 30 minutes |
| Concurrent runs per computer | 1 at a time | 1 at a time |
| Max log output per run | 1 MB | 1 MB |
| Input file retention | Deleted 24 hours after a run ends | Deleted 24 hours after a run ends |
| Output file retention | Deleted after 7 days | Deleted after 7 days |
| Computers (runners) per workspace | 1 | 1 |
Recipients never pay, and downgrading from Pro to Free deletes nothing. If a colleague needs to hand your script more than 8 files in one go - say, a folder of images or a month of daily CSVs - have them upload a single ZIP file (up to 25 MB) and let your script unpack it before running.
Step 1: Make your script take arguments instead of hard-coded paths
Before you connect the script to Button, make sure it doesn't rely on hard-coded file paths on your desktop or interactive prompts that wait for someone to type into a terminal. It should take its inputs as command-line arguments: argparse in Python, commandArgs() in R, a param() block in PowerShell, or $1 and $2 in bash.
For an upload-and-download tool, take each input file path as an argument, and take an output folder path as another argument where your script writes the finished files. Fixed flags like --input-file are part of the command you approve on your machine; your colleagues only fill in the values for the form fields you expose.
Here is a minimal Python example that takes an input CSV and an output folder, processes the file, and writes the result into that folder:
import argparse
import os
import shutil
parser = argparse.ArgumentParser()
parser.add_argument("--input-file", required=True)
parser.add_argument("--output-dir", required=True)
args = parser.parse_args()
os.makedirs(args.output_dir, exist_ok=True)
out_path = os.path.join(args.output_dir, "processed.csv")
# Replace this with your actual CSV, Excel, PDF, or image processing logic
shutil.copyfile(args.input_file, out_path)
print("Wrote", out_path)
Step 2: Install the runner and publish the page
- Sign in at
https://button.bitgate.dev. - Install the Button runner on your computer (macOS, Linux, or Windows) by running the one-line command the site shows you -
curlon macOS and Linux, or PowerShell on Windows. Each workspace pairs with one computer, and pairing a new computer replaces the previous one. - In the runner's local setup page, pick your program and set up the command. The runner pins the exact command you approve on that computer by hash, and when it runs, every form value is passed to your program as its own argument with no shell, and a value can't start with
-. - Describe the inputs you want on the form. You can add file inputs alongside text, number, yes/no, and choice fields.
- Publish the tool and invite your colleagues.
Once published, your tool gets its own page. Colleagues open the link from their invite email, sign in with Google or a one-time email code, fill in the form, press Run, and download the output files when the script finishes. They don't install anything. Every run is logged with who ran it and when, and you can revoke a person's access or set it to expire at any time. If you change the tool later, people have to confirm the new version before running it.
When another tool is the better choice
Button isn't the right fit for every file-processing script. Use something else if:
- Your files are larger than 25 MB each or 100 MB per run. Streamlit's
st.file_uploaderaccepts files up to 200 MB by default (server.maxUploadSize), and a custom Flask or FastAPI app lets you set your own upload limits. - You can't leave your computer on and online. Because Button runs the job on your machine, the tool page shows Offline whenever your computer is asleep or disconnected, and it shows Busy while someone else's run is in progress (since it runs one job at a time). If people need the page to work when your machine is off, host an app on a server or use Streamlit Community Cloud.
- Your job takes longer than 30 minutes, or you need two runs happening at the same time. Button runs one job at a time on your one paired computer, for up to 30 minutes each.
- You want an interactive dashboard instead of a run-and-download form. If colleagues need to filter tables live or tweak charts in the browser rather than uploading a file, pressing Run, and downloading the result, Streamlit is built for that.
FAQ
Do the uploaded files stay on my computer?
No. While the script itself runs on your computer rather than in Button's cloud, the form values, uploaded input files, and output files are relayed through Button's servers between your colleague's browser and your machine. Button deletes input files 24 hours after a run ends and deletes output files after 7 days.
What happens if two colleagues press Run at the same time?
A computer runs one job at a time. While a run is happening, the tool page shows Busy instead of Ready, and it goes back to Ready when the run finishes (or shows Offline if your computer is turned off or offline).
How do I let someone upload more than 8 files in a single run?
Have them put the files into a single .zip archive and upload that to a file field, then unzip it inside your script before processing. Each file can be up to 25 MB, with up to 100 MB total per run.
Do the people I share the page with need a Python environment or a paid account?
No, they install nothing and never pay. They open the link from their invite email in a browser, sign in with Google or a one-time email code, and run the form.
Can a colleague inject shell commands through a text field?
Not through Button. The runner only executes the exact command you approved on your computer (pinned by hash), passes every form value directly to the program as its own argument without a shell, and blocks values that start with -. Your script should still treat each value as data, not as a command to run.
Last updated
Put your script behind a form
Button turns a script on your computer into a web form. Colleagues sign in, fill it in, press Run and download the results. Free for 1 tool and 3 people.