Releases: psychopy/psychopy
2026.1.0
Introducing PsychoPy Studio
PsychoPy Studio is a full rebuild of the PsychoPy desktop app using web-based libraries (Svelte and Electron). The underlying experiment engine (the PsychoPy library) is still Python, but Studio provides a smoother, more user-friendly interface (think drag and drop routines…) and better version independence with useVersion.
As always, the code is fully open source, you can view and contribute here. Eventually, PsychoPy Studio will replace the standalone PsychoPy app, but we plan to maintain both for a few major releases while the dust settles.
Read more about PsychoPy Studio here
PsychoPy 2026.1.0
Same as any release, PsychoPy 2026.1.0 also comes with fixes and improvements to PsychoPy itself.
Highlights
- A known bug with Mac retina screens which was affecting the reliability of frame timings has been fixed by @mdcutone in #7502
- Object detection in camera streams by @mdcutone in #7490
- Add support for displaying plots with
ImageStimby @mdcutone in #7382
Improvements
- Store pilot mode in data file by @TEParsons in #7378
- Add method to TrialHandler for queueing a trial as next by @TEParsons in #7412
- Add dedicated paramCtrl for PsychoPy version by @TEParsons in #7542
- Add a "FontFinder" for a more easily externally callable methods to get fonts known to PsychoPy by @TEParsons in #7448
- Added various methods for representing PsychoPy objects as JSON, for compatability with PsychoPy Studio by @TEParsons in #7359, #7353, #7376, #7377, #7368, #7380, #7388, #7484, #7491, #7514
Fixes
- Find dialog now includes params with "set during..." matching the search term by @TEParsons in #7385
- Added code to maintain external spectral calibration by @wadelab in #7372
- Allow multiple joysticks when using the Pyglet backend by @mdcutone in #7414
- Correctly get the number of joystick devices by @rlaboiss in #7434
- Use expanding lists to avoid index errors with buttonboxes and sensors by @TEParsons in #7458
- Stop all playback Components (Sound, Movie, etc.) when experiment ends by @TEParsons in #7461
- Fix SyntaxError due to docstring by @mscheltienne in #7479
- clamp StairHandler intensity when step size is negative by @stephenmjerge in #7475
- Fix AttributeError: KeyboardDevice missing _buffers attribute wo PTB by @wadelab in #7494
- ExperimentHandler not saving extraInfo to wide text by @davidmwatson in #7374
- Fix Auto->JS isinstance(list) to Array by @stephenmjerge in #7533
- Fix bug in preferences dialog handling speakers named "default" by @TEParsons in #7499
- Allow iohub errors in clients to be logged by @mdcutone in #7532
- Fixed issue with plugins window not opening by @peircej in #7546
- Fixes errors when opening Monitor Center (wx app) by @mdcutone in #7541
- Changes to support 3D mesh rendering again by @mdcutone in #7530
- Revert to old-style file list ctrl by @TEParsons in #7558
- Use a dedicated param ctrl for choosing validators by @TEParsons in #7421
Other Changes
- Move code to run PsychoJS locally out of the app and into the library by @TEParsons in #7467
- Move psydat2csv to tools by @TEParsons in #7487
New contributors
- @wadelab made their first contribution in #7372
- @stephenmjerge made their first contribution in #7475
- @Emil-Ant made their first contribution in #7519
Testing and documentation improvements
- @Emil-Ant ( #7519 )
- @RebeccaHirst ( #7455 )
- @TEParsons ( #7515, #7481 )
- @mdcutone ( #7468 )
Full Changelog: 2025.2.4...2026.1.0
2025.2.4
What's changed
Fixes
- Fix error & missing refresh token when logging in from saved details by @TEParsons in #7513
- Fix error when loading some experiments by @TEParsons in #7504
Documentation
Full Changelog: 2025.2.3...2025.2.4
2025.2.3
GitLab compatibility
Pavlovia will soon be upgrading to a newer version of GitLab in which authentication tokens have a maximum shelf life of 2 hours. This release of PsychoPy is the first to include automatic token renewal, allowing you to be seamlessly re-authenticated without having to manually log back in. In prior versions, once Pavlovia has updated, you will have to manually log back in every 2 hours. We apologise for the inconvenience, unfortunately this is essential for your data security.
Bug Fixes
- Fix bug where renamed user details weren't available from Pavlovia by @TEParsons in #7460
- Fixed param control text color selection when using system dark theme by @mdcutone in #7457
- When FontManager finds multiple matching fonts, sort them so the same one is always chosen by @TEParsons in #7464
- Make sure validation columns (stim.validator.started, etc.) exist even if validation fails by @TEParsons in #7466
- Don't use SetFont on Linux by @TEParsons in #7477
- When Pavlovia auth token expires, send a refresh request by @TEParsons in #7478
- Fixed
Mouse.getPos()returningfloat64typed objects instead offloatby @mdcutone in #7462 - Better handle when stimulus stop validation fails by @TEParsons in #7485
Documentation improvements
Full Changelog: 2025.2.2...2025.2.3
2025.2.2
What's Changed
- Fix unformatted warning when a device fails to scan by @TEParsons in #7445
- Visual validator was ignoring "Find threshold/sensor" params by @TEParsons in #7444
- Save unfinished mic recordings if the experiment is ended by e.g. pressing escape by @TEParsons in #7452
- Dollar label wasn't showing for some params by @TEParsons in #7436
- Silence confusing message in MouseComponent about params updating by @TEParsons in #7440
- Fix bug with saving data each trial by @TEParsons in #7437
Full Changelog: 2025.2.1...2025.2.2
2025.2.1
What's Changed
- Loop type wasn't updating loop ctrls by @TEParsons in #7366 7360
- Circle was triggering unecessary warnings about deprecation by @TEParsons in #7364
- Make Component dialog pages scrollable by @TEParsons in #7365
- Fix setting Polygon num. vertices each repeat by @TEParsons in #7379
- Fixed muting on movie player warmup and volume setter methods by @mdcutone in #7375
- Fixes for mouse input via
eventswhen multiple window backends are installed by @mdcutone in #7367 - Fix iohub recording state in Builder ouput by @mdcutone in #7370
- Fixed incorrect func ref in
getAllJoysticks()by @mdcutone in #7392 - Add mic query plist by @peircej in #7402
- Fix how the timeout param is written in SerialDevice by @TEParsons in #7400
- Importing
psychopy.appwhen writing scripts was slowing things down and breaking Use Version by @TEParsons in #7409 - Reset volume when movie is reloaded by @mdcutone in #7417
- Fix view and projection matrices not being applied before first flip by @mdcutone in #7381
- Handle when there's a file called "untitled.psyexp" in the app's root directory by @TEParsons in #7395
- Allow Session to use a relative path for its root folder by @TEParsons in #7399
- Add an "Add multiple" button to file list params by @TEParsons in #7383
- Fix confusing message on Sound when given a variable by @TEParsons in #7428
- Fixed loading ioHub settings from XML by device class name by @mdcutone in #7433
Full Changelog: 2025.2.0...2025.2.1
PsychoPy 2025.2.0
Highlights
🐍 = Works locally
🌐 = Works online
🐍 Reworked SerialComponent to give more control over what data is sent
🐍 Device Manager to consolidate working with a single device at multiple points in a study or across studies
🐍 Much better performance for movie playing and camera recordings (better buffering of frames)
🐍 Revamped photometer classes for easier gamma calibration
Other Changes
- Add example demo script for extracting hdf5 data by @RebeccaHirst in #7223
- fixed iohub compatibility with PyObjC>=8.0
- Plugin/package manager performance improvements by @mdcutone in #7194
- Fixes for numpy>=2.0 by @aforren1 in #7229
- New
endCurrentRoutinemethod for ExperimentHandler by @TEParsons in #7213 - Better updating of local language translation files by @hsogo in #7230
- Don't cancel upcoming iteration in TrialHandler2 if on last trial by @TEParsons in #7240
- Enable discarding previous responses in Button Box akin to keyboard by @TEParsons in #7250
- Fix erronious alert about missing transcriber (for Mic) when running locally by @TEParsons in #7258
- Don't search for experiment fonts if the experiment folder is the home directory by @TEParsons in #7257
- Allow overriding user preferences directory with PSYCHOPY_CONFIG_FOLDER environment variable by @wieluk in #7207
- Sound sensor volume was adjusted for 255 (when threshold is 0-1) by @TEParsons in #7261
- Enforce a minimum size on multiline text params by @TEParsons in #7263
- Fixed error when adding data to a row that's out of bounds by @TEParsons in #7266
- Handle when allowedKeys is just 1 multi-character string (e.g. "return") online by @TEParsons in #7268
- Improved movie playback performance for
MovieStimusing ffpyplayer by @mdcutone in #7264 - Handle when a file added to runner has been deleted by @TEParsons in #7276
- For Sesssion, set experiment start time and name in Experiment run function by @TEParsons in #7281
- Improved camera performance in local studies by @mdcutone in #7267
- Fix package indexing subprocess crash by @mdcutone in #7293
- Catch "Bad perspective string" errors on app launch by @TEParsons in #7298
- Fix gamma calibration button in Monitor Center by @TEParsons in #7304
- Better handling of legacy params for device Components by @TEParsons in #7308
- Various UI fixes by @TEParsons in #7311 #7312 and by @mdcutone in #7323
- Allow ButtonBox responses to be compared to dicts with the correct fields by @TEParsons in #7306
- Give more information when an image fails to load by @TEParsons in #7310
- Fix legacy photometer finding methods by @TEParsons in #7321
- Give more informative error when conditions file has duplicate names by @TEParsons in #7324
- Maintain aspect ratio when MovieStim size is None by @TEParsons in #7325
- Deprecated psychopy.voicekey (move to psychopy-legacy) by @TEParsons in #7326
New Contributors
- @bschiller8 made their first contribution in #7114
Full Changelog: 2025.1.1...2025.2.0
PsychoPy 2025.1.1
What's Changed
Bugs Fixed
- Respect existing opacity when setting a color by @TEParsons in #7200
- Fixed missing references to GazePoint sample event class by @mdcutone in #7228
- Fixed moviepy import for window frame capture by @sh4r11f in #7218
Other Changes
- Limiting PTB version for now (to 3.0.19, the last free version) by @peircej in #7204
- Allow numpy>=2.0 (#7229) by @mdcutone in #7231
- Many fixes to docs by @TEParsons and @RebeccaHirst
New Contributors
Full Changelog: 2025.1.0...2025.1.1
PsychoPy 2025.1.0
Highlights
🐍 = Works locally
🌐 = Works online
- 🐍 Visual and audio timing validators to provide automated always-on timing tests of your stimuli
- Movie and audio improvements:
- 🌐 YouTube as movie stimulus accessible from Builder
- 🐍 Improved audio playback and recording with automatic resampling (no more "sample rate not supported" errors!)
- 🐍🌐 Microphone now has a
.getCurrentVolumemethod - 🐍 Support for infinite duration recordings with
Microphone
- 🌐 Face API accessible from Builder (via the new Face API Plugin
- 🐍 Any visual stimulus can now be used as an eyetracker calibration point
- 🐍 Sound Sensor Component: Get True/False responses from a microphone or specialised VoiceKey device
- 🐍 Supported VoiceKey devices: BBTK T-Pad, Cedrus RB / Riponda / StimTracker
New and Improved
- First steps towards modernizing the OpenGL pipeline to support Pyglet v2.0
- Joystick class now supports deadzones, plugins and button mappings by @mdcutone in #6967
- Make install behaviour consistent between plugins and packages by @TEParsons in #6742
- Allow Sound to play on different speakers in the same experiment by @TEParsons in #6760
- Disable pip version check in plugin manager by @mh105 in #6772
- Allow Session window to switch between fullscreen and windowed by @TEParsons in #6783
- Added "force end Routine" option for Sound Component by @TEParsons in #6766
- When a trial is skipped, end all Routines in current trial by @TEParsons in #6785
- Allow Sound to receive a Microphone object as its sound by @TEParsons in #6793
- Better default behaviour for SpeakerDevice by @TEParsons in #6811
- After adding a listener, return it by @TEParsons in #6822
- After skipping/rewinding a trial, return the new current trial by @TEParsons in #6819
- Better logging around audio recording / playback by @TEParsons in #6820
- Better logging behaviour for SerialDevice by @TEParsons in #6827
- Added the option for an expVersion into the SettingsComponent by @peircej in #6830
- Device responses should indicate which device they came from by @TEParsons in #6838
- Run Microphone.saveClips in endExperiment by @TEParsons in #6845
- Allow recursive callOnFlip() calls by @zeyus in #6814
- Include details about sample rate and channels in SpeakerDevice by @TEParsons in #6867
- Clearer wording in console when experiment finishes by @TEParsons in #6866
- Add function to get parameters from stimuli, which you can use to recreate it by @TEParsons in #6801
- Allow eyetracker plugins to control how their eyetracker appears in Builder by @TEParsons in #6779
- Add option to save data during Static Component period by @TEParsons in #6882
- Log device responses by default by @TEParsons in #6881
- Add "update" button to plugin dialog if plugin version isn't the latest by @TEParsons in #6919
- Improve app load speed by caching icons added by plugins by @TEParsons in #6934
- Allow non-WASAPI audio devices by @zeyus in #6922
- Misc. improvements to app launch speed by @TEParsons in #6941
- In Components from not installed plugins, add a button to get the plugin by @TEParsons in #6891
- Added case-sensitive search and search-as-you-type in Builder search by @jderrfuss in #6947
- Add "Find" buttons to Builder and Coder ribbons by @TEParsons in #6956
- Add option for regex search in Builder search dialog by @TEParsons in #6955
- Replace default participant ID in pilot mode with "pilot" by @TEParsons in #6976
- Allow automatic resampling of audio files by @TEParsons in #6987
- Allow plugin Components to specify themselves as hidden by @TEParsons in #6988
- Trim silence from start of default.mp3 by @TEParsons in #6994
- Added error type for devices not found to make it easier to catch errors by @TEParsons in #7019
- set user path for different python versions on OSX framework by @mh105 in #6769
- Better error catching when loading plugins by @TEParsons in #6877
- Silently handle when prefs/appData files are broken by @TEParsons in #7047
- Add menu item & shortcut for Experiment Settings (CTRL+SHIFT+X) by @TEParsons in #7050
- Allow for infinite duration audio recording by @mdcutone in #7060
- Compile translation files when building the package by @hsogo in #7079
- Remove sampleRate and channels params from Microphone, both of these can be detected reliably now by @TEParsons in #7090
- Add a keyboard shortcut (ALT+SHIFT+R) for "Reveal in file explorer" by @TEParsons in #7093
- Ask in Builder before downloading a Google Font by @TEParsons in #7082
- Added loops to Builder search by @TEParsons in #7096
- Style a greater range of filetypes in Coder file browser by @TEParsons in #7117
- Define "PILOTING" variable online as well as locally by @TEParsons in #7109
- Add option to always show mouse in pilot mode by @TEParsons in #7120
- New splash screen with OST logo by @TEParsons in #7134
- Add (online only) support for YouTube videos in MovieStim by @TEParsons in #6989
- Track installed files to prevent accidental deletion of user files during uninstallation by @mdcutone in #7175
Fixed
- Allow Microphone to be found by name OR index by @TEParsons in #6756
- Allow Speaker to be specified using name rather than index by @TEParsons in #6759
- More helpful error message when importing function that's moved to a plugin by @TEParsons in #6774
- Append user packages correctly to PYTHONPATH by @mh105 in #6770
- Clear listeners when closing a MicrophoneDevice by @TEParsons in #6803
- Allow Microphone to be closed and reopened multiple times in same session by @TEParsons in #6804
- Fix KeyError when closing microphone by @TEParsons in #6805
- Distinguish between a trial that's been skipped and a trial that's currently skipping by @TEParsons in #6807
- Reset session clock to 0 before running an experiment by @TEParsons in #6817
- Reset the global clock after a pause, otherwise onflip timing breaks by @TEParsons in #6816
- Fixes to device listeners by @TEParsons in #6824
- Fix removing devices from listener loop by @TEParsons in #6825
- Remove child devices when a device is removed from DeviceManager by @TEParsons in #6831
- Fix bug where "ERROR" logs showed up as "DEPRECATION" by @TEParsons in #6836
- Alerts were displaying in wrong tab by @TEParsons in #6870
- Coder was always opening with psychopyApp.py open by @TEParsons in #6875
- When installing packages, don't add
--userflag if--targetis specified by @mdcutone in #6879 - Fix Linux iohub keyboard relative import error by @zeyus in #6858
- Fixed `AttributeError` calling `refreshPackages` on Py3.9 by @mdcutone in #6909
- Better error handling when getting recording from mic that's still recording by @TEParsons in #6908
- Fix nonslip timing issue in JS code by @TEParsons in #6928
- If ioHub keypress made with only key code, use value for key name by @TEParsons in #6894
- Fixed `cielch2rgb` handling of multidim arrays by @mdcutone in #6961
- Fixes to opening files from Coder's file browser panel by @TEParsons in #6983
- Avoid "untitled.psyexp does not exist" warning by @TEParsons in #6992
- Remove "Close" buttons from Runner tabs by @TEParsons in #6997
- Sound online was sometimes marked as already finished on second iteration of a loop by @TEParsons in #7016
- Slashes in project names were causing Pavlovia sync to error by @TEParsons in #7017
- Opening the same experiment in two Builder windows caused the prefs file to be saved wrong, leading to an error next time the app started by @TEParsons in #7045
- Variables in Button Component callbacks weren't defined properly online by @TEParsons in #7048
- Fix rendering error when max Routine duration was set in frames by @TEParsons in #7057
- Fixed app failing to start on Windows using `pythonw.exe` by @mdcutone in #7061
- Removed package search as PyPi no longer supports searching by API by @mdcutone in #7064
- Fix error at staircase in loop by @hideh1231 in #7062
- Fixed Google API transcriber options not appearing in mic component by @mdcutone in #7075
- If a Mic was never started, it would error on saving recording by @TEParsons in #7076
- Fixes import error when using Neon (Pupil Labs eyetracker) in coder by @domstoppable in #7083
- Downgrade "git not installed" error to a warning by @TEParsons in #7086
- Handle when allowed keys is a code snippet (not just a variable) by @TEParsons in #7085
- Fix confusing item type error in Form by @TEParsons in #7084
- All unknown parameters were labelled "Plugin" by @TEParsons in #7089
- Silence unnecessary "ERROR" log in Polygon by @TEParsons in #7091
- Installing package in Builder via pyproject.toml wasn't working by @TEParsons in #7100
- Make it clearer that Slider labels/ticks can't be set each trial by @TEParsons in #7112
- Coder file modified dialog shouldn't block Builder by @TEParsons in #7111
- Fix timing issue when a non-slip Routine was force ended in JS by @TEParsons in #7110
- Parameters weren't being set on first frame in JS by @TEParsons in #7113
- Remove unnecessary font check which was causing a sporadic error by @TEParsons in #7126
- Better handle (and warn about) deprecated color attributes by @TEParsons in #7127
- Some params of Button Component were missed online by @TEParsons in #7128
- MovieStim was still marked as finished after seeking back to 0 by @TEParsons in #7131
- App ribbon labels were wrong color in dark mode by @TEParsons in #7132
- Catch when a plugin doesn't have a version number by @TEParsons in #7133
- Update TextStim after setting opacity to trigger a re-...
2024.2.5
Fixes
- Sending experiment to Runner was sometimes (wrongly) toggling pilot/run mode by @TEParsons in #6945
- Fixed ioHub sometimes failing to close when script terminates by @mh105 in #6949
- Fixed ioHub process staying alive after crash by @mdcutone in #6938
- Standalone Routine names weren't handling name conflicts properly by @Lance-Buescher1 in #6999 and #7000
- Documentation fixes by @jfkominsky @mhyeun and @RebeccaHirst
New Contributors
- @Lance-Buescher1 made their first contribution in #6999
- @mhyeun made their first contribution in #7035
Full Changelog: 2024.2.4...2024.2.5
2024.2.4
Fixes this release
- Recreate .js file on run when piloting in JS by @TEParsons in #6920
- App failing to start on MacOS if all windows closed on last app close by @peircej in #6926
- Fix nonslip timing issue in Builder-generated PsychoJS code by @TEParsons in #6921
Full Changelog: 2024.2.3...2024.2.4