diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,5 +1,10 @@
 # ChangeLog for yesod-core
 
+## 1.6.16
+
+* Add `jsAttributesHandler` to run arbitrary Handler code before building the
+  attributes map for the script tag generated by `widgetFile` [#1622](https://github.com/yesodweb/yesod/pull/1622)
+
 ## 1.6.15
 
 * Move `redirectToPost` JavaScript form submission from HTML element to
diff --git a/src/Yesod/Core/Class/Yesod.hs b/src/Yesod/Core/Class/Yesod.hs
--- a/src/Yesod/Core/Class/Yesod.hs
+++ b/src/Yesod/Core/Class/Yesod.hs
@@ -249,6 +249,16 @@
     jsAttributes :: site -> [(Text, Text)]
     jsAttributes _ = []
 
+    -- | Same as @jsAttributes@ but allows you to run arbitrary Handler code
+    --
+    -- This is useful if you need to add a randomised nonce value to the script
+    -- tag generated by @widgetFile@. If this function is overridden then
+    -- @jsAttributes@ is ignored.
+    --
+    -- @since 1.6.16
+    jsAttributesHandler :: HandlerFor site [(Text, Text)]
+    jsAttributesHandler = jsAttributes <$> getYesod
+
     -- | Create a session backend. Returning 'Nothing' disables
     -- sessions. If you'd like to change the way that the session
     -- cookies are created, take a look at
@@ -520,7 +530,9 @@
 widgetToPageContent :: Yesod site
                     => WidgetFor site ()
                     -> HandlerFor site (PageContent (Route site))
-widgetToPageContent w = HandlerFor $ \hd -> do
+widgetToPageContent w = do
+  jsAttrs <- jsAttributesHandler
+  HandlerFor $ \hd -> do
   master <- unHandlerFor getYesod hd
   ref <- newIORef mempty
   unWidgetFor w WidgetData
@@ -564,7 +576,7 @@
                 ^{mkScriptTag s}
             $maybe j <- jscript
                 $maybe s <- jsLoc
-                    <script src="#{s}" *{jsAttributes master}>
+                    <script src="#{s}" *{jsAttrs}>
                 $nothing
                     <script>^{jelper j}
         |]
@@ -627,7 +639,7 @@
         let path' = TE.decodeUtf8With TEE.lenientDecode $ W.rawPathInfo r
         defaultMessageWidget "Not Found" [hamlet|<p>#{path'}|]
     provideRep $ return $ object ["message" .= ("Not Found" :: Text)]
-    provideRep $ return $ ("Not Found" :: Text)
+    provideRep $ return ("Not Found" :: Text)
 
 -- For API requests.
 -- For a user with a browser,
@@ -651,7 +663,7 @@
         let apair u = ["authentication_url" .= rend u]
             content = maybe [] apair (authRoute site)
         return $ object $ ("message" .= ("Not logged in"::Text)):content
-    provideRep $ return $ ("Not logged in" :: Text)
+    provideRep $ return ("Not logged in" :: Text)
 
 defaultErrorHandler (PermissionDenied msg) = selectRep $ do
     provideRep $ defaultLayout $ defaultMessageWidget
@@ -670,7 +682,7 @@
                     <li>#{msg}
         |]
     provideRep $ return $ object ["message" .= ("Invalid Arguments" :: Text), "errors" .= ia]
-    provideRep $ return $ ("Invalid Arguments: " <> T.intercalate " " ia)
+    provideRep $ return ("Invalid Arguments: " <> T.intercalate " " ia)
 
 defaultErrorHandler (InternalError e) = do
     $logErrorS "yesod-core" e
diff --git a/yesod-core.cabal b/yesod-core.cabal
--- a/yesod-core.cabal
+++ b/yesod-core.cabal
@@ -1,5 +1,5 @@
 name:            yesod-core
-version:         1.6.15
+version:         1.6.16
 license:         MIT
 license-file:    LICENSE
 author:          Michael Snoyman <michael@snoyman.com>
