diff --git a/.travis.yml b/.travis.yml
index a98d547978f37b593d2445b3d554ddda67f46eed..e7fcd8b5d1c782a1655889f42ef9802d52513f59 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -23,6 +23,9 @@ matrix:
   - python: 3.6
     env: TOX_ENV=py36
 
+  - python: 3.6
+    env: TOX_ENV=isort
+
   - python: 3.6
     env: TOX_ENV=check-newsfragment
 
diff --git a/changelog.d/3540.misc b/changelog.d/3540.misc
new file mode 100644
index 0000000000000000000000000000000000000000..99dcad8e46eb0f1467e858c4bc07bde485472786
--- /dev/null
+++ b/changelog.d/3540.misc
@@ -0,0 +1 @@
+check isort for each PR
diff --git a/synapse/config/consent_config.py b/synapse/config/consent_config.py
index e22c731aadec0d0224af4867522fbef065a0079e..cec978125b8e7d282e16f38b436748399b001031 100644
--- a/synapse/config/consent_config.py
+++ b/synapse/config/consent_config.py
@@ -15,6 +15,7 @@
 
 from ._base import Config
 
+
 DEFAULT_CONFIG = """\
 # User Consent configuration
 #
diff --git a/synapse/config/logger.py b/synapse/config/logger.py
index a87b11a1dff02df68ea04e6713dd21c7f15232a7..cc1051057cfeabbd8eff27c0f02547e36832f995 100644
--- a/synapse/config/logger.py
+++ b/synapse/config/logger.py
@@ -29,6 +29,7 @@ from synapse.util.versionstring import get_version_string
 
 from ._base import Config
 
+
 DEFAULT_LOG_CONFIG = Template("""
 version: 1
 
diff --git a/synapse/config/server_notices_config.py b/synapse/config/server_notices_config.py
index 3c39850ac6a0d3d484f9a49755366bc036b13105..91b08446b768e858e9d06dbed97b63c8bbbf7365 100644
--- a/synapse/config/server_notices_config.py
+++ b/synapse/config/server_notices_config.py
@@ -16,6 +16,7 @@ from synapse.types import UserID
 
 from ._base import Config
 
+
 DEFAULT_CONFIG = """\
 # Server Notices room configuration
 #
diff --git a/synapse/http/client.py b/synapse/http/client.py
index d6a0d75b2b3561f294ffa698aea84000bf685393..0622a69e86b7c1c0656ce1a550763183c61ecb17 100644
--- a/synapse/http/client.py
+++ b/synapse/http/client.py
@@ -26,9 +26,11 @@ from OpenSSL.SSL import VERIFY_NONE
 from twisted.internet import defer, protocol, reactor, ssl, task
 from twisted.internet.endpoints import HostnameEndpoint, wrapClientTLS
 from twisted.web._newclient import ResponseDone
-from twisted.web.client import Agent, BrowserLikeRedirectAgent, ContentDecoderAgent
 from twisted.web.client import FileBodyProducer as TwistedFileBodyProducer
 from twisted.web.client import (
+    Agent,
+    BrowserLikeRedirectAgent,
+    ContentDecoderAgent,
     GzipDecoder,
     HTTPConnectionPool,
     PartialDownloadError,
diff --git a/synapse/http/site.py b/synapse/http/site.py
index 21e26f9c5e442bab8194938f1b5736de2b604fc8..41dd974cea4cbf991c6da3a31ac05d3276cdb181 100644
--- a/synapse/http/site.py
+++ b/synapse/http/site.py
@@ -20,7 +20,7 @@ from twisted.web.server import Request, Site
 
 from synapse.http import redact_uri
 from synapse.http.request_metrics import RequestMetrics
-from synapse.util.logcontext import LoggingContext, ContextResourceUsage
+from synapse.util.logcontext import ContextResourceUsage, LoggingContext
 
 logger = logging.getLogger(__name__)
 
diff --git a/synapse/rest/__init__.py b/synapse/rest/__init__.py
index 75c2a4ec8e5521745d9c053694a80afc389c2b09..0d69d37f7eda2a627ff31ad7b9ddc8255d730758 100644
--- a/synapse/rest/__init__.py
+++ b/synapse/rest/__init__.py
@@ -15,11 +15,21 @@
 
 from synapse.http.server import JsonResource
 from synapse.rest.client import versions
-from synapse.rest.client.v1 import admin, directory, events, initial_sync
 from synapse.rest.client.v1 import login as v1_login
-from synapse.rest.client.v1 import logout, presence, profile, push_rule, pusher
 from synapse.rest.client.v1 import register as v1_register
-from synapse.rest.client.v1 import room, voip
+from synapse.rest.client.v1 import (
+    admin,
+    directory,
+    events,
+    initial_sync,
+    logout,
+    presence,
+    profile,
+    push_rule,
+    pusher,
+    room,
+    voip,
+)
 from synapse.rest.client.v2_alpha import (
     account,
     account_data,
diff --git a/synapse/rest/client/v1/admin.py b/synapse/rest/client/v1/admin.py
index 01c3f2eb0449fd04a96b26de9226db645d8745c6..2dc50e582b14f275a08d48d14401cd54010db78a 100644
--- a/synapse/rest/client/v1/admin.py
+++ b/synapse/rest/client/v1/admin.py
@@ -24,9 +24,9 @@ from synapse.api.constants import Membership
 from synapse.api.errors import AuthError, Codes, NotFoundError, SynapseError
 from synapse.http.servlet import (
     assert_params_in_dict,
-    parse_json_object_from_request,
     parse_integer,
-    parse_string
+    parse_json_object_from_request,
+    parse_string,
 )
 from synapse.types import UserID, create_requester
 
diff --git a/synapse/rest/client/v1/initial_sync.py b/synapse/rest/client/v1/initial_sync.py
index 00a1a99feb800caf96531d691d44019025daffb3..fd5f85b53ee6879d954e823a383f1b971a4e1b96 100644
--- a/synapse/rest/client/v1/initial_sync.py
+++ b/synapse/rest/client/v1/initial_sync.py
@@ -15,8 +15,8 @@
 
 from twisted.internet import defer
 
-from synapse.streams.config import PaginationConfig
 from synapse.http.servlet import parse_boolean
+from synapse.streams.config import PaginationConfig
 
 from .base import ClientV1RestServlet, client_path_patterns
 
diff --git a/synapse/rest/client/v2_alpha/devices.py b/synapse/rest/client/v2_alpha/devices.py
index aded2409be5a7624843be6feef3e55142c2255b7..9b75bb1377484b62c2c76eb67d1e76c532400f51 100644
--- a/synapse/rest/client/v2_alpha/devices.py
+++ b/synapse/rest/client/v2_alpha/devices.py
@@ -19,9 +19,9 @@ from twisted.internet import defer
 
 from synapse.api import errors
 from synapse.http.servlet import (
+    RestServlet,
     assert_params_in_dict,
     parse_json_object_from_request,
-    RestServlet
 )
 
 from ._base import client_v2_patterns, interactive_auth_handler
diff --git a/synapse/rest/media/v1/identicon_resource.py b/synapse/rest/media/v1/identicon_resource.py
index b3217eff538b6895d26176937fcfae3244644dee..bdbd8d50dd474b173752c8fc8dd3c7a021bf2be6 100644
--- a/synapse/rest/media/v1/identicon_resource.py
+++ b/synapse/rest/media/v1/identicon_resource.py
@@ -14,10 +14,10 @@
 
 from pydenticon import Generator
 
-from synapse.http.servlet import parse_integer
-
 from twisted.web.resource import Resource
 
+from synapse.http.servlet import parse_integer
+
 FOREGROUND = [
     "rgb(45,79,255)",
     "rgb(254,180,44)",
diff --git a/synapse/storage/schema/delta/48/group_unique_indexes.py b/synapse/storage/schema/delta/48/group_unique_indexes.py
index 2233af87d770cc9b3f46afd63b18f7d614400aa2..ac4ac66cd4d00a95e621d036b4f421b907ec201e 100644
--- a/synapse/storage/schema/delta/48/group_unique_indexes.py
+++ b/synapse/storage/schema/delta/48/group_unique_indexes.py
@@ -15,6 +15,7 @@
 from synapse.storage.engines import PostgresEngine
 from synapse.storage.prepare_database import get_statements
 
+
 FIX_INDEXES = """
 -- rebuild indexes as uniques
 DROP INDEX groups_invites_g_idx;
diff --git a/tox.ini b/tox.ini
index 61a20a10cb14d4b05dd43747d81f7b18c88fd48f..c7491690c570bcd27ec192f949ab0f71e712dade 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,5 +1,5 @@
 [tox]
-envlist = packaging, py27, py36, pep8
+envlist = packaging, py27, py36, pep8, isort
 
 [testenv]
 deps =
@@ -103,10 +103,14 @@ deps =
     flake8
 commands = /bin/sh -c "flake8 synapse tests {env:PEP8SUFFIX:}"
 
+[testenv:isort]
+skip_install = True
+deps = isort
+commands = /bin/sh -c "isort -c -sp setup.cfg -rc synapse tests"
 
 [testenv:check-newsfragment]
 skip_install = True
 deps = towncrier>=18.6.0rc1
 commands =
    python -m towncrier.check --compare-with=origin/develop
-basepython = python3.6
\ No newline at end of file
+basepython = python3.6