SDKs
Python
Flask

Flask Integration

Capture errors and request context from Flask applications.

Installation

pip install statly-observe

Setup

from flask import Flask
from statly_observe import Statly
from statly_observe.integrations.flask import init_flask
 
# Initialize SDK first
Statly.init(
    dsn='https://[email protected]/your-org',
    environment='production',
)
 
app = Flask(__name__)
 
# Attach to Flask app
init_flask(app)
 
@app.route('/')
def hello():
    return 'Hello World'
 
@app.route('/error')
def error():
    raise ValueError('Test error')
 
if __name__ == '__main__':
    app.run()

What's Captured

Request Context

For each error, the integration captures:

  • HTTP method and URL
  • Path and query string
  • Headers (sanitized)
  • Form data and JSON body (sanitized)
  • Remote IP address
  • Flask endpoint name

Automatic Sanitization

Sensitive data is automatically filtered:

Headers:

  • authorization
  • cookie
  • x-api-key
  • x-auth-token

Body/Form fields:

  • password
  • secret
  • token
  • api_key
  • credit_card
  • ssn

Breadcrumbs

The integration automatically adds breadcrumbs for:

  • Each request (method, URL, path)
  • Each response (status code, duration)

With Authentication

Set user context from Flask-Login or similar:

from flask import Flask, g
from flask_login import current_user
from statly_observe import Statly
from statly_observe.integrations.flask import init_flask
 
app = Flask(__name__)
init_flask(app)
 
@app.before_request
def set_user_context():
    if current_user.is_authenticated:
        Statly.set_user(
            id=str(current_user.id),
            email=current_user.email,
            username=current_user.username,
        )

Manual Capture

Capture errors manually with additional context:

from flask import Flask, request
from statly_observe import Statly
from statly_observe.integrations.flask import init_flask
 
app = Flask(__name__)
init_flask(app)
 
@app.route('/api/orders', methods=['POST'])
def create_order():
    try:
        order = process_order(request.json)
        return {'order_id': order.id}
    except PaymentError as e:
        Statly.capture_exception(e, context={
            'order_total': request.json.get('total'),
            'payment_method': request.json.get('method'),
        })
        return {'error': 'Payment failed'}, 400

With Blueprints

The integration works with Flask blueprints:

from flask import Flask, Blueprint
from statly_observe import Statly
from statly_observe.integrations.flask import init_flask
 
api = Blueprint('api', __name__, url_prefix='/api')
 
@api.route('/users')
def list_users():
    return {'users': []}
 
app = Flask(__name__)
init_flask(app)
app.register_blueprint(api)

Error Handling

Custom error handlers still work:

from flask import Flask
from statly_observe import Statly
from statly_observe.integrations.flask import init_flask
 
app = Flask(__name__)
init_flask(app)
 
@app.errorhandler(404)
def not_found(error):
    # 404s are not captured by default
    return {'error': 'Not found'}, 404
 
@app.errorhandler(500)
def server_error(error):
    # 500s are captured automatically
    return {'error': 'Server error'}, 500

Full Example

from flask import Flask, request, g
from statly_observe import Statly
from statly_observe.integrations.flask import init_flask
 
Statly.init(
    dsn='https://[email protected]/your-org',
    environment='production',
)
 
app = Flask(__name__)
init_flask(app)
 
@app.before_request
def before_request():
    # Track request timing
    g.start_time = time.time()
 
    # Add custom breadcrumb
    Statly.add_breadcrumb(
        message=f'{request.method} {request.path}',
        category='http',
        level='info',
    )
 
@app.after_request
def after_request(response):
    duration = time.time() - g.start_time
    Statly.add_breadcrumb(
        message=f'Response {response.status_code}',
        category='http',
        level='info',
        data={'duration_ms': duration * 1000},
    )
    return response
 
@app.route('/api/data')
def get_data():
    data = fetch_data()
    return {'data': data}
 
if __name__ == '__main__':
    app.run(debug=True)