Add Parameters to a Processing Algorithm

The parameters are the algorithm's interface. Get them right and the framework builds a dialog, validates the input, populates the field picker from the chosen layer, exposes everything to batch mode and the modeller, and hands your code clean typed values. Get them wrong and users type layer names into text boxes.

This recipe belongs to Processing Provider Plugins. It covers the parameter types you will actually use, defaults and optional inputs, parameters that depend on each other, and the correct way to read each kind inside processAlgorithm().

One definition, three interfacesEach parameter definition declares a type, a label, a default and whether it is optional. From that single declaration the framework generates a widget in the algorithm dialog, a column in the batch interface, and a named key in the parameters dictionary that scripts pass to processing dot run. Nothing about the interface is written by the plugin author.Declare the input; the framework builds the restyour definitionsFeatureSource INPUTField GROUP FIELDNumber MIN AREASink OUTPUTthe generated dialoglayer pickerfield list from that layerspin box with limitsoutput file chooserbatch modeone column eachfilled per rowprocessing.runa dictionary keyedby your names

Prerequisites

Declare the parameters

from qgis.core import (QgsProcessingAlgorithm, QgsProcessing,
                       QgsProcessingParameterFeatureSource,
                       QgsProcessingParameterField,
                       QgsProcessingParameterNumber,
                       QgsProcessingParameterEnum,
                       QgsProcessingParameterBoolean,
                       QgsProcessingParameterFeatureSink)

INPUT = "INPUT"
GROUP_FIELD = "GROUP_FIELD"
MIN_AREA = "MIN_AREA"
UNITS = "UNITS"
KEEP_EMPTY = "KEEP_EMPTY"
OUTPUT = "OUTPUT"


class SummariseParcelsAlgorithm(QgsProcessingAlgorithm):

    def initAlgorithm(self, config=None):
        self.addParameter(QgsProcessingParameterFeatureSource(
            INPUT, self.tr("Parcel layer"),
            [QgsProcessing.TypeVectorPolygon]))

        self.addParameter(QgsProcessingParameterField(
            GROUP_FIELD, self.tr("Group by field"),
            parentLayerParameterName=INPUT,
            type=QgsProcessingParameterField.Any))

        self.addParameter(QgsProcessingParameterNumber(
            MIN_AREA, self.tr("Minimum area"),
            type=QgsProcessingParameterNumber.Double,
            defaultValue=0.0, minValue=0.0))

        self.addParameter(QgsProcessingParameterEnum(
            UNITS, self.tr("Report units"),
            options=[self.tr("square metres"), self.tr("hectares")],
            defaultValue=1))

        self.addParameter(QgsProcessingParameterBoolean(
            KEEP_EMPTY, self.tr("Keep groups with no parcels"),
            defaultValue=False))

        self.addParameter(QgsProcessingParameterFeatureSink(
            OUTPUT, self.tr("Summary")))

Breakdown: Constants for the parameter names keep the definition and the reads in sync — a typo in a string literal produces None at run time rather than an error at load time. QgsProcessingParameterFeatureSource restricted to polygons means the picker only offers polygon layers, which removes a whole class of user mistake; it also accepts a selection-only checkbox and a file path, all for free. The field parameter's parentLayerParameterName is what makes its dropdown populate from whichever layer the user picked, and it is the difference between a field picker and a text box. The enum stores an index, not the label, which is the most common misreading of the parameters dictionary.

Read them correctly

Each parameter type has its own accessor, and using the wrong one is the usual source of a TypeError deep in an algorithm.

    def processAlgorithm(self, parameters, context, feedback):
        source = self.parameterAsSource(parameters, INPUT, context)
        field = self.parameterAsString(parameters, GROUP_FIELD, context)
        minimum = self.parameterAsDouble(parameters, MIN_AREA, context)
        units_index = self.parameterAsEnum(parameters, UNITS, context)
        keep_empty = self.parameterAsBool(parameters, KEEP_EMPTY, context)

        if source is None:
            raise QgsProcessingException(self.invalidSourceError(parameters, INPUT))

        divisor = 10000.0 if units_index == 1 else 1.0
        ...

Breakdown: parameterAsSource() returns a QgsProcessingFeatureSource, which honours the user's "selected features only" choice automatically — this is why algorithms should take a source rather than a layer. The enum accessor returns the index into the options list you declared, so map it to meaning explicitly rather than comparing against a translated string, which would break in any other language. parameterAsDouble and parameterAsBool handle the conversion from whatever the caller passed, including the strings that arrive from the command line. Checking the source for None and raising with invalidSourceError() gives the framework's standard, translated message instead of an AttributeError three lines later.

Optional parameters and advanced sections

Not every input belongs on the front of the dialog.

        overlay = QgsProcessingParameterFeatureSource(
            "OVERLAY", self.tr("Clip to boundary"),
            [QgsProcessing.TypeVectorPolygon], optional=True)
        overlay.setFlags(overlay.flags() | QgsProcessingParameterDefinition.FlagAdvanced)
        self.addParameter(overlay)

        tolerance = QgsProcessingParameterNumber(
            "TOLERANCE", self.tr("Snapping tolerance"),
            type=QgsProcessingParameterNumber.Double, defaultValue=0.01)
        tolerance.setFlags(tolerance.flags() | QgsProcessingParameterDefinition.FlagAdvanced)
        self.addParameter(tolerance)

Breakdown: optional=True lets the user leave it blank, and your code must then handle None — which is exactly the point, because an optional clip layer is a genuinely different code path. FlagAdvanced moves the parameter into the collapsible Advanced section, which is where anything with a good default belongs; a dialog with four visible fields and six advanced ones is far more approachable than one with ten. Both flags are combined with the existing flags rather than replacing them, using the bitwise or — assigning the flag directly clears everything else, including the hidden and expression flags.

Parameter type, widget, accessorFeature source parameters produce a layer picker and are read with parameter as source. Field parameters produce a field dropdown tied to a parent layer and are read as a string. Number parameters produce a spin box and are read as double or integer. Enum parameters produce a dropdown and are read as an index. Feature sink parameters produce an output chooser and are read with parameter as sink.Reading a parameter with the wrong accessor is the usual bugparameter typewidgetaccessorFeatureSourcelayer picker plus selectionparameterAsSourceFielddropdown from parent layerparameterAsStringEnumdropdown of your optionsparameterAsEnum — an indexFeatureSinkoutput chooserparameterAsSink — two values

Validate before the work starts

Parameters that are individually valid can be jointly wrong — a field that is not numeric, a distance in the wrong units for the layer's CRS, two layers in incompatible projections.

    def checkParameterValues(self, parameters, context):
        source = self.parameterAsSource(parameters, INPUT, context)
        field = self.parameterAsString(parameters, GROUP_FIELD, context)

        if source is not None and field:
            index = source.fields().lookupField(field)
            if index >= 0 and not source.fields().at(index).isNumeric():
                if self.parameterAsEnum(parameters, UNITS, context) == 1:
                    return False, self.tr("Hectare output needs a numeric field")

        return super().checkParameterValues(parameters, context)

Breakdown: checkParameterValues() runs before the algorithm starts and returns a tuple of validity and message; the framework shows the message in the dialog and refuses to run. Doing this here rather than raising inside processAlgorithm() matters in batch mode, where a hundred rows should be validated before any of them execute rather than failing on row sixty. Always delegate to super() at the end so the framework's own checks — mandatory parameters, writable outputs — still apply.

Where validation belongs in batch modeValidating in checkParameterValues runs before execution, so a batch of a hundred rows reports the problem immediately and nothing is written. Validating inside processAlgorithm runs per row, so sixty rows are processed and written before the bad one fails, leaving a partial output nobody asked for.A hundred rows deserve to fail before the first one runscheckParameterValuesruns before executionmessage shown in the dialognothing written, nothing to undoinside processAlgorithmruns per rowrow 61 raises60 outputs already written

Outputs are parameters too

The sink declared alongside the inputs above is what gives the user an output chooser, and reading it inside processAlgorithm() is slightly unusual because it returns two values.

        # inside processAlgorithm
        sink, dest_id = self.parameterAsSink(
            parameters, OUTPUT, context, fields, QgsWkbTypes.NoGeometry, source.sourceCrs())
        if sink is None:
            raise QgsProcessingException(self.invalidSinkError(parameters, OUTPUT))
        return {OUTPUT: dest_id}

Breakdown: A sink parameter gives the user the full output chooser — a file, a GeoPackage layer, a PostGIS table, a temporary layer — without your code caring which. parameterAsSink() returns two values, the sink to write to and the destination id to return, and returning the id is what lets the framework add the result to the map, chain it into a model, or report its path. Declaring NoGeometry here produces an attribute-only table, which is exactly right for a summary and a common thing to get wrong by copying a geometry-carrying example.

QGIS version compatibility

QGIS versionPythonNotes
3.22 LTR3.9All parameter types shown, plus flags and checkParameterValues.
3.28 LTR3.9Identical.
3.34 LTR3.12Baseline for this page.
3.40 / 3.443.12Adds further parameter types (point cloud layers, area and volume numbers); existing ones unchanged.

Parameter names are part of your public interface: models and scripts reference them. Renaming one breaks every saved model that uses the algorithm, so choose plain uppercase names early and keep them.

Troubleshooting

  • The field dropdown is empty. parentLayerParameterName is missing or names a parameter that does not exist.
  • parameterAsEnum() returns 0 for everything. You are comparing against labels; it returns the index into options.
  • An optional parameter crashes the algorithm. It is None when blank. Handle that branch explicitly.
  • The advanced section is empty and everything is visible. The flag was assigned rather than combined with the existing flags.
  • Batch mode fails on every row. Validation is inside processAlgorithm() instead of checkParameterValues().
  • The output never appears on the map. processAlgorithm() did not return the destination id in its dictionary.

Conclusion

Declare parameters with the specific type that matches the input — feature source, field with a parent layer, number with limits, enum with options — give everything a sensible default, and push anything with a good default into the advanced section. Read each with its matching accessor, remembering that enums give indices and sinks give two values, and validate combinations in checkParameterValues() so batch runs fail before they start rather than halfway through.

Frequently Asked Questions

Should I take a layer or a feature source? A source. It honours the "selected features only" option and accepts a file path as well as a loaded layer, so the algorithm works in more contexts for no extra code.

How do I let the user enter an expression? Use QgsProcessingParameterExpression with a parent layer, which gives the expression builder with the right fields — see Evaluate a QGIS Expression in PyQGIS.

Can a parameter depend on another parameter's value? Field, expression and band parameters can name a parent layer. Beyond that, validate the combination in checkParameterValues(); the dialog cannot rebuild itself dynamically.

What is the difference between a sink and a file output? A sink writes features and can target any provider; a file destination parameter is just a path, for algorithms writing something that is not a layer, such as a report.

How do defaults appear in batch mode? Each row starts from the declared defaults, so good defaults save the most typing exactly where there is the most of it.

Can I give a parameter its own help text? Yes — setHelp() on the definition adds a tooltip, and shortHelpString() on the algorithm can describe each parameter in the panel beside the dialog. Both are worth filling in for anything whose units or expectations are not obvious from the label alone.

Do parameter labels need translating? Yes — wrap them in self.tr(). They are the algorithm's entire visible interface, as covered in Translate a QGIS Plugin with Qt Linguist.