Factory.ai

Open-Source Wikis

/

Stable Diffusion WebUI

/

Systems

/

Script callbacks

AUTOMATIC1111/stable-diffusion-webui

Script callbacks

Active contributors: AUTOMATIC1111, Aarni Koskela, w-e-w, catboxanon

Purpose

A registry of named hooks that scripts and extensions can subscribe to. The script-callbacks API is the recommended way to extend the webui without subclassing Script — it's lighter, callable from anywhere, and orderable across extensions.

All callbacks live in modules/script_callbacks.py. The pattern is uniform: an on_<event>(callback) registration function, and a <event>_callback(...) dispatcher called by the core code.

How registration works

from modules import script_callbacks

def my_handler(demo, app):
    print("the UI just started")

script_callbacks.on_app_started(my_handler)

Internally, every on_* function appends to a list inside callback_map keyed on the event name. When the core code dispatches the event, it iterates the list (in user-defined order, taking metadata.ini [callbacks/...] ordering hints into account) and calls each callback. Exceptions are caught and reported via errors.report so a single broken extension doesn't crash the request.

Available callbacks

The full list at the time of writing — see the source for parameter signatures and any per-callback notes. Categories are informal but match the order in script_callbacks.py.

Lifecycle

Callback Fires when Typical use
on_before_ui Before the Gradio UI is built Late initialisation that needs shared.opts
on_app_started(demo, app) After Gradio launch, with the FastAPI app Register custom HTTP routes
on_before_reload Before a UI reload Save state, close handles
on_script_unloaded When a script is being unloaded Cleanup

Model

Callback Fires when
on_model_loaded(sd_model) After model_hijack.hijack(sd_model)
on_list_unets(callback) When sd_unet enumerates available UNets

UI construction

Callback Fires when
on_ui_tabs() Returns extra tabs as [(component, label, elem_id), ...]
on_ui_train_tabs(params) Adds tabs to the Train sub-tab
on_ui_settings() Register settings via shared.options_templates.update(...)
on_before_component(component, **kwargs) Before each Gradio component is created
on_after_component(component, **kwargs) After each component is created — match by elem_id

Image saving

Callback Fires when
on_before_image_saved(params) Before save_image writes the file; params: ImageSaveParams
on_image_saved(params) After the file is written
on_image_grid(params) When a grid image is being assembled

Generation

Callback Fires when
on_extra_noise(params) Just before noise is added; params: ExtraNoiseParams carries noise, x, xi
on_cfg_denoiser(params) At every sampler step, before inner_model runs; params: CFGDenoiserParams carries x, image_cond, sigma, sampling_step, total_sampling_steps, text_cond, text_uncond, denoiser
on_cfg_denoised(params) After inner_model runs but before CFG is applied
on_cfg_after_cfg(params) After CFG; lets you modify the predicted noise/x
on_post_sample(params) After sampling but before postprocessing; params: PostSampleArgs

Optimisations and infotext

Callback Fires when
on_list_optimizers(callback) When attention optimisations are enumerated
on_infotext_pasted(infotext, params) When the user pastes a generation parameters string
on_before_token_counter(params) Before the prompt token-counter runs

Parameter dataclasses

Several callbacks pass a dedicated parameter object. The most useful are:

class ImageSaveParams:
    image: PIL.Image
    p: StableDiffusionProcessing
    filename: str
    pnginfo: dict   # mutate this to change PNG metadata

class CFGDenoiserParams:
    x: torch.Tensor              # latent being denoised
    image_cond: torch.Tensor     # for img2img / inpainting
    sigma: torch.Tensor
    sampling_step: int
    total_sampling_steps: int
    text_cond: torch.Tensor      # positive prompt embedding
    text_uncond: torch.Tensor    # negative prompt embedding
    denoiser: CFGDenoiser        # access the wrapper itself

class ExtraNoiseParams:
    noise: torch.Tensor
    x: torch.Tensor
    xi: torch.Tensor

class CFGDenoisedParams:
    x: torch.Tensor
    sampling_step: int
    total_sampling_steps: int
    inner_model

Mutating these dataclasses in your callback feeds the modified value back into the pipeline.

Ordering

Two layers of ordering apply:

  1. Within a single callback list, registration order. Extensions registered later run later by default.
  2. metadata.ini [callbacks/<name>] blocks let an extension declare Before = ext1, ext2 and/or After = ext3 for a specific callback. The runner then does a topological sort.

script_callbacks.add_callback(...) and sort_callbacks(...) implement this. Most extension authors don't need to think about it; ControlNet+ADetailer is the canonical case where ordering matters.

Removing callbacks

Two helpers exist for testing and reload:

  • remove_current_script_callbacks() — removes every callback registered by the script that's currently being loaded. Used internally during the script-reload path.
  • remove_callbacks_for_function(callback_func) — exact-function removal.

These are rarely useful in normal extension code; they exist for the UI-reload flow that closes and re-creates shared.demo.

Integration points

  • The processing pipeline (processing.md) calls cfg_*, extra_noise, before_image_saved, image_saved, image_grid directly.
  • The UI builder (ui.md) calls before_ui_callback, ui_tabs_callback, ui_settings_callback, before_component_callback, after_component_callback.
  • The model loader (models.md) calls model_loaded_callback and list_unets_callback.
  • The reload loop in webui.py calls app_reload_callback and script_unloaded_callback.
  • The infotext utilities call infotext_pasted_callback whenever the "Read generation parameters" button fires.

Entry points for modification

  • Add a new callback — declare a callbacks_<name> list in callback_map, an on_<name>(callback) registration function, and a <name>_callback(...) dispatcher. Then call the dispatcher from the core code at the right point. Document the params object if you add one.
  • Modify an existing callback's signature — don't, unless you're adding optional kwargs at the end. Extensions in the wild rely on positional argument shapes.
  • Debug callback failureserrors.report logs the offending script's filename. Set --loglevel DEBUG for the full traceback.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Script callbacks – Stable Diffusion WebUI wiki | Factory