A lightweight web tool to convert JSON data into viewable tables with CSV export capability. Designed for internal team use with zero data storage.
-
Multiple Input Methods
- 📁 File upload (drag & drop supported)
- 📋 Paste JSON directly
- 🌐 Fetch from external APIs
-
Authentication Support (for API fetching)
- API Key (custom header)
- Basic Authentication
- Bearer Token
- Query Parameter Token
-
Data Processing
- Handles nested JSON objects
- Displays nested data as expandable tables
- Preview first 25 rows
- Export ALL rows to CSV
-
Privacy First
- No data storage - everything processed in-memory
- No databases, no logs, no persistence
- Session-based processing only
- Python 3.11+
- pip
# Clone or download the project
cd json-table-tool
# Create virtual environment (optional but recommended)
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
# Install dependencies
pip install -r requirements.txt
# Run the application
python app.pyOpen your browser to http://localhost:5000
Render offers a free tier perfect for internal tools. No credit card required for free tier.
- ✅ Free tier available
- ✅ No data persistence on free tier (exactly what we need)
- ✅ Easy GitHub integration
- ✅ HTTPS included
- ✅ Simple deployment process
Push the code to a GitHub repository (can be private):
cd json-table-tool
git init
git add .
git commit -m "Initial commit"
git remote add origin https://github.com/YOUR_USERNAME/json-table-tool.git
git push -u origin main- Go to render.com
- Sign up with GitHub (recommended for easy repo access)
- Verify your email
Option A: Using render.yaml (Blueprint)
- In Render dashboard, click "New +" → "Blueprint"
- Connect your GitHub repository
- Render will auto-detect
render.yamland configure everything - Click "Apply"
- Wait for deployment (2-3 minutes)
Option B: Manual Setup
- In Render dashboard, click "New +" → "Web Service"
- Connect your GitHub repository
- Configure:
- Name:
json-table-converter(or your choice) - Region: Choose closest to your team
- Branch:
main - Runtime:
Python 3 - Build Command:
pip install -r requirements.txt - Start Command:
gunicorn "app:create_app()" --bind 0.0.0.0:$PORT
- Name:
- Select Free plan
- Click "Create Web Service"
After deployment completes:
- Your app will be available at:
https://json-table-converter.onrender.com - (The exact URL depends on your service name)
Since this is for internal team use, consider these options:
- Don't share the URL publicly
- Free tier URLs are hard to guess
- Sufficient for most internal tools
Add this to app.py before the routes:
from functools import wraps
from flask import request, Response
def check_auth(username, password):
return username == 'your_team' and password == 'your_secret_password'
def authenticate():
return Response(
'Authentication required', 401,
{'WWW-Authenticate': 'Basic realm="Login Required"'}
)
def requires_auth(f):
@wraps(f)
def decorated(*args, **kwargs):
auth = request.authorization
if not auth or not check_auth(auth.username, auth.password):
return authenticate()
return f(*args, **kwargs)
return decorated
# Then add @requires_auth decorator to routes:
@app.route('/')
@requires_auth
def index():
...Render's paid tiers support IP allowlisting for stricter access control.
Run directly on any Linux server with Python 3.11+:
# Clone and install
git clone https://github.com/YOUR_USERNAME/json-table-tool.git
cd json-table-tool
python -m venv venv
source venv/bin/activate
pip install -r requirements.txt
# Set production environment variables
export SECRET_KEY="your-random-secret-key-here"
export FLASK_DEBUG=0
# Run with gunicorn
gunicorn "app:create_app()" --bind 0.0.0.0:8000 --workers 4Create /etc/systemd/system/json-table-tool.service:
[Unit]
Description=JSON Table Converter
After=network.target
[Service]
User=www-data
Group=www-data
WorkingDirectory=/opt/json-table-tool
Environment="SECRET_KEY=your-random-secret-key-here"
Environment="FLASK_DEBUG=0"
ExecStart=/opt/json-table-tool/venv/bin/gunicorn "app:create_app()" --bind 127.0.0.1:8000 --workers 4
Restart=always
[Install]
WantedBy=multi-user.targetsudo systemctl enable json-table-tool
sudo systemctl start json-table-toolPair with Nginx for TLS termination and static file serving:
server {
listen 443 ssl;
server_name jsontable.yourcompany.com;
ssl_certificate /etc/letsencrypt/live/jsontable.yourcompany.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/jsontable.yourcompany.com/privkey.pem;
location /static/ {
alias /opt/json-table-tool/static/;
expires 1d;
}
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}# Dockerfile
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["gunicorn", "app:create_app()", "--bind", "0.0.0.0:8000", "--workers", "4"]docker build -t json-table-tool .
docker run -p 8000:8000 \
-e SECRET_KEY="your-random-secret-key-here" \
json-table-tool# docker-compose.yml
services:
app:
build: .
ports:
- "8000:8000"
environment:
- SECRET_KEY=your-random-secret-key-here
- FLASK_DEBUG=0
- RATE_LIMIT_PROCESS=30/minute
- RATE_LIMIT_EXPORT=60/minute
restart: unless-stoppeddocker compose up -dnpm install -g @railway/cli
railway login
railway init
railway upcurl -L https://fly.io/install.sh | sh
fly launch
fly deploySet these in production for any deployment method:
| Variable | Required | Default | Description |
|---|---|---|---|
SECRET_KEY |
Yes | dev-secret-key-... |
CSRF token signing key. Generate with python -c "import secrets; print(secrets.token_hex(32))" |
FLASK_DEBUG |
No | 0 |
Set to 0 in production |
MAX_UPLOAD_SIZE |
No | 10485760 |
Max request body in bytes (10 MB) |
PREVIEW_ROW_LIMIT |
No | 25 |
Rows shown in preview table |
API_FETCH_TIMEOUT |
No | 30 |
Seconds before API fetch times out |
API_FETCH_MAX_RESPONSE |
No | 10485760 |
Max API response size in bytes |
RATE_LIMIT_PROCESS |
No | 30/minute |
Rate limit on /process endpoint |
RATE_LIMIT_EXPORT |
No | 60/minute |
Rate limit on export endpoints |
RATE_LIMIT_DEFAULT |
No | 120/minute |
Default rate limit for all routes |
- Click "Upload File" tab
- Drag & drop a
.jsonfile or click to browse - Click "Convert to Table"
- Click "Paste JSON" tab
- Paste your JSON into the text area
- Click "Convert to Table"
- Click "Fetch from API" tab
- Enter the API endpoint URL
- Select authentication method if needed:
- API Key: Enter header name and key
- Basic Auth: Enter username and password
- Bearer Token: Enter your token
- Query Param: Enter parameter name and value
- Click "Convert to Table"
- After conversion, click "Export" to see format options:
- CSV — Comma-separated values (generated instantly in your browser)
- TSV — Tab-separated values (generated instantly in your browser)
- Excel —
.xlsxfile via server-side generation
- All formats export ALL rows (not just the preview)
// Array of objects (ideal)
[
{"id": 1, "name": "Alice"},
{"id": 2, "name": "Bob"}
]
// Object with array property
{
"data": [
{"id": 1, "name": "Alice"},
{"id": 2, "name": "Bob"}
]
}
// Nested objects
{
"users": {
"data": [
{"id": 1, "profile": {"name": "Alice", "age": 30}}
]
}
}- Nested objects display as inline tables
- Arrays of objects show expandable preview (first 5 items)
- Complex nested data is JSON-stringified in CSV export
- No data logging: Server processes data in memory only
- No database: No persistence layer configured
- CSRF protection: All POST routes protected via Flask-WTF tokens
- SSRF prevention: API fetch validates DNS, blocks private/internal IPs
- Rate limiting: Configurable per-route rate limits (Flask-Limiter)
- Security headers: CSP, X-Frame-Options, X-Content-Type-Options, Referrer-Policy
- HTTPS: Render provides free SSL/TLS; use Nginx/Let's Encrypt for self-hosted
- Stateless: Each request is independent, no session state
- Validate your JSON at jsonlint.com
- Check for trailing commas
- Ensure proper quote usage
- Verify the API URL is correct
- Check authentication credentials
- Ensure the API returns JSON (not XML/HTML)
- API must be accessible from Render's servers
- Maximum upload size: 10MB
- For larger files, consider pagination or pre-processing
# Run in debug mode
export FLASK_DEBUG=1
python app.py
# Run tests
python -m pytest tests/ -vMIT License - Feel free to modify and use internally.
For issues or feature requests, create an issue in the repository or contact your team admin.