One macro in printer.cfg replaces the slicer's end G-code. Paste it, set your park position, put END_PRINT in the slicer, and it also runs when you cancel a print.
A Klipper end print macro is a [gcode_macro END_PRINT] section in printer.cfg that retracts the filament, then lifts and parks the nozzle. It finishes by turning off the heaters, the part fan and the motors. Your slicer’s end G-code becomes one line: END_PRINT. The macro below does all of that and stays inside your axis limits.
[gcode_macro END_PRINT]
description: Retract, lift and park, then turn off heaters, fan and motors
gcode:
{% set retract = params.RETRACT|default(3)|float %}
{% set lift = params.Z_LIFT|default(10)|float %}
{% set pos = printer.gcode_move.gcode_position %}
{% set origin = printer.gcode_move.homing_origin %}
{% set max = printer.toolhead.axis_maximum %}
{% set z_park = [pos.z + lift, max.z - origin.z]|min %}
{% set x_park = max.x - 10 %} ; placeholder: your park X
{% set y_park = max.y - 10 %} ; placeholder: your park Y
{% if retract > 0 and printer[printer.toolhead.extruder].can_extrude %}
M83 ; relative extrusion
G1 E-{retract} F1800 ; pull filament back from the nozzle
{% endif %}
{% if "xyz" in printer.toolhead.homed_axes %}
G90 ; absolute moves
G1 Z{z_park} F600 ; lift off the print
G1 X{x_park} Y{y_park} F6000 ; park the head
{% endif %}
TURN_OFF_HEATERS ; every heater, chamber included
M107 ; part cooling fan off
BED_MESH_CLEAR ; drop the mesh
M220 S100 ; reset speed override
M221 S100 ; reset flow override
M84 ; motors off
What should a Klipper END_PRINT macro do?
A Klipper END_PRINT macro should retract a few millimeters of filament while the nozzle is still hot. It then lifts the nozzle clear of the print and parks the head out of the way. Last, it turns off every heater and the part fan, clears the bed mesh and disables the motors.
| Job |
Command |
Why |
| Retract |
G1 E-3 |
Stops ooze and stringing on the finished part |
| Lift and park |
G1 Z…, G1 X… Y… |
Keeps the hot nozzle off the print and leaves the part reachable |
| Heaters off |
TURN_OFF_HEATERS |
Klipper: “Turn off all heaters” |
| Fan off |
M107 |
Turns off the part cooling fan |
| Clear mesh |
BED_MESH_CLEAR |
Klipper: “It is recommended to put this in your end-gcode” |
| Motors off |
M84 |
Releases the steppers |
Klipper’s sample END_PRINT covers the same ground with fixed relative moves. It retracts 3 mm while stepping 2 mm away in X and Y, lifts 10 mm, then sends M84. The macro above uses the same 3 mm and 10 mm as defaults, adds a park position and checks the limits.
How to add an END_PRINT macro in Klipper
- Paste the macro. Add the END_PRINT section above to printer.cfg, or to a file it includes.
- Set the park position. Change the
x_park and y_park lines to coordinates inside your travel that leave the print reachable.
- Restart Klipper. Restart from your web interface, or send
RESTART from the console.
- Test it by hand. Home the printer and heat the hotend above 170 C so the retract runs. Then send
END_PRINT.
- Replace the slicer’s end G-code. Delete everything in the slicer’s end G-code field and enter
END_PRINT.
Klipper’s Slicers page recommends exactly this split, since changes to the macro “do not require re-slicing.”
What each part of the macro does
RETRACT and Z_LIFT. Optional parameters with defaults of 3 and 10 mm. END_PRINT Z_LIFT=50 lifts higher for one print. Parameters are covered in macro parameters.
gcode_position and homing_origin. Klipper’s status reference describes gcode_position as positions “that one might directly send to a G1 command.” Subtracting homing_origin.z (the Z offset set by SET_GCODE_OFFSET) from axis_maximum.z keeps the lift below the top of the Z axis.
- The
can_extrude check. It is true only once the hotend reaches min_extrude_temp, which defaults to 170 C. On a cold printer, END_PRINT skips the retract instead of raising an error.
- The
homed_axes check. It skips the moves if X, Y or Z has not been homed.
M220 S100 and M221 S100. These undo speed and flow overrides set from the web interface during the print. In Klipper’s source, an M220 speed factor stays in force until it is changed again or Klipper restarts.
Klipper evaluates the whole template before running any of it. Its command templates page warns that state changes made by a macro “will not be visible during the evaluation of the macro.” Every position the macro reads dates from before END_PRINT started. Reading gcode_position again after the lift would still return the old Z, so the park height is computed once, up front.
END_PRINT or PRINT_END: what to call the end macro
Either name works. Klipper has no built-in end command, so the slicer must call exactly the name your [gcode_macro] defines. Klipper’s documentation uses END_PRINT. Voron’s stock configs use PRINT_END. A mismatch shows up in the console as Unknown command:"END_PRINT". The same rule applies to the start macro, covered in PRINT_START.
How to run END_PRINT when you cancel a print
Klipper’s built-in CANCEL_PRINT only stops the file and clears the pause state. END_PRINT sits at the end of a file that never finishes, so it does not run. The command exists only when printer.cfg has a [pause_resume] section.
Mainsail’s and Fluidd’s client macros (mainsail.cfg or fluidd.cfg) replace CANCEL_PRINT with one that retracts 5 mm and turns off the heaters and fan. Before it stops the print, it runs one line you supply in _CLIENT_VARIABLE:
[gcode_macro _CLIENT_VARIABLE]
variable_user_cancel_macro: "END_PRINT RETRACT=0"
gcode:
RETRACT=0 avoids a second retract on top of the client macro’s 5 mm.
Without those client macros, wrap the built-in command yourself:
[gcode_macro CANCEL_PRINT]
rename_existing: CANCEL_PRINT_BASE
gcode:
END_PRINT
CANCEL_PRINT_BASE
A print that stops on an error runs on_error_gcode from [virtual_sdcard] instead. Its default is TURN_OFF_HEATERS. Mainsail’s config sets it to CANCEL_PRINT, so the cancel setup above covers errors too.
Fixing END_PRINT errors
- “Extrude below minimum temp”. The retract ran with the hotend under
min_extrude_temp. Retract before TURN_OFF_HEATERS, or keep the can_extrude check.
- “Move out of range”. A lift or park move went past
position_max. The min clamp handles Z, so check that the park X and Y sit inside your travel.
- “Must home axis first”. END_PRINT ran on an unhomed printer. The
homed_axes check prevents it.
- The hotend fan keeps running. That is normal. A
[heater_fan] runs until the hotend drops below heater_temp, which defaults to 50 C.
- The Z axis drops when the motors turn off. Delete
M84. Voron’s stock PRINT_END leaves it out. Klipper’s idle timeout still runs TURN_OFF_HEATERS and M84 after 600 seconds by default.
A chamber heater defined as [heater_generic] is switched off by TURN_OFF_HEATERS with the rest. The heater itself is set up in chamber heater control.