diff --git a/core/badge-urls/make-badge-url.js b/core/badge-urls/make-badge-url.js
index 6646e95ab9787e77ec237ed695fad81dfac8fbd2..3fd23042e6d56e3e187f1e6ea3ae489cae558314 100644
--- a/core/badge-urls/make-badge-url.js
+++ b/core/badge-urls/make-badge-url.js
@@ -71,9 +71,43 @@ function staticBadgeUrl({
   return `${baseUrl}/badge/${path}.${format}${suffix}`
 }
 
+function dynamicBadgeUrl({
+  baseUrl,
+  datatype,
+  label,
+  dataUrl,
+  query,
+  prefix,
+  suffix,
+  color,
+  style,
+  format = 'svg',
+}) {
+  const queryParams = {
+    label,
+    url: dataUrl,
+    query,
+    style,
+  }
+
+  if (color) {
+    queryParams.color = color
+  }
+  if (prefix) {
+    queryParams.prefix = prefix
+  }
+  if (suffix) {
+    queryParams.suffix = suffix
+  }
+
+  const outQueryString = queryString.stringify(queryParams)
+  return `${baseUrl}/badge/dynamic/${datatype}.${format}?${outQueryString}`
+}
+
 module.exports = {
   badgeUrlFromPath,
   badgeUrlFromPattern,
   encodeField,
   staticBadgeUrl,
+  dynamicBadgeUrl,
 }
diff --git a/core/badge-urls/make-badge-url.spec.js b/core/badge-urls/make-badge-url.spec.js
index 491035a59aa96a02646813f536ab1018e6f40059..3ca61b9fcccaf73a2ff39eb7a6b763facb23fe6d 100644
--- a/core/badge-urls/make-badge-url.spec.js
+++ b/core/badge-urls/make-badge-url.spec.js
@@ -6,6 +6,7 @@ const {
   badgeUrlFromPattern,
   encodeField,
   staticBadgeUrl,
+  dynamicBadgeUrl,
 } = require('./make-badge-url')
 
 describe('Badge URL generation functions', function() {
@@ -79,4 +80,50 @@ describe('Badge URL generation functions', function() {
       color: 'blue',
     }).expect('/badge/-blue-blue.svg')
   })
+
+  test(dynamicBadgeUrl, () => {
+    const dataUrl = 'http://example.com/foo.json'
+    const query = '$.bar'
+    const prefix = 'value: '
+    given({
+      baseUrl: 'http://img.example.com',
+      datatype: 'json',
+      label: 'foo',
+      dataUrl,
+      query,
+      prefix,
+      style: 'plastic',
+    }).expect(
+      [
+        'http://img.example.com/badge/dynamic/json.svg',
+        '?label=foo',
+        `&prefix=${encodeURIComponent(prefix)}`,
+        `&query=${encodeURIComponent(query)}`,
+        '&style=plastic',
+        `&url=${encodeURIComponent(dataUrl)}`,
+      ].join('')
+    )
+    const suffix = '<- value'
+    const color = 'blue'
+    given({
+      baseUrl: 'http://img.example.com',
+      datatype: 'json',
+      label: 'foo',
+      dataUrl,
+      query,
+      suffix,
+      color,
+      style: 'plastic',
+    }).expect(
+      [
+        'http://img.example.com/badge/dynamic/json.svg',
+        '?color=blue',
+        '&label=foo',
+        `&query=${encodeURIComponent(query)}`,
+        '&style=plastic',
+        `&suffix=${encodeURIComponent(suffix)}`,
+        `&url=${encodeURIComponent(dataUrl)}`,
+      ].join('')
+    )
+  })
 })
diff --git a/frontend/components/customizer/customizer.js b/frontend/components/customizer/customizer.js
index 0e1d12debfe25315c30ca49b8b22728f5ca6e4e8..b3e35540f6c9ce20cedae205e1a8ccdd6ac2bfda 100644
--- a/frontend/components/customizer/customizer.js
+++ b/frontend/components/customizer/customizer.js
@@ -1,7 +1,7 @@
 import React from 'react'
 import PropTypes from 'prop-types'
 import clipboardCopy from 'clipboard-copy'
-import { staticBadgeUrl } from '../../lib/badge-url'
+import { staticBadgeUrl } from '../../../core/badge-urls/make-badge-url'
 import { generateMarkup } from '../../lib/generate-image-markup'
 import { Badge } from '../common'
 import PathBuilder from './path-builder'
@@ -61,12 +61,11 @@ export default class Customizer extends React.Component {
     if (pathIsComplete) {
       src = this.generateBuiltBadgeUrl()
     } else {
-      src = staticBadgeUrl(
+      src = staticBadgeUrl({
         baseUrl,
-        'preview',
-        'some parameters missing',
-        'lightgray'
-      )
+        label: 'preview',
+        message: 'some parameters missing',
+      })
     }
     return (
       <p>
diff --git a/frontend/components/development/logo-page.js b/frontend/components/development/logo-page.js
index cf9577a89c109c3fe9d392e608484446a89fc558..0fecbe4bd6ffa27fcafb5e07bf08ebef0e3fdc2d 100644
--- a/frontend/components/development/logo-page.js
+++ b/frontend/components/development/logo-page.js
@@ -1,7 +1,7 @@
 import React from 'react'
 import PropTypes from 'prop-types'
 import styled from 'styled-components'
-import { staticBadgeUrl } from '../../lib/badge-url'
+import { staticBadgeUrl } from '../../../core/badge-urls/make-badge-url'
 import { baseUrl } from '../../constants'
 import Meta from '../meta'
 import Header from '../header'
@@ -33,16 +33,24 @@ const NamedLogoTable = ({ logoNames }) => (
           <td>
             <Badge
               alt={`logo: ${name}`}
-              src={staticBadgeUrl(baseUrl, 'named logo', name, 'blue', {
-                logo: name,
+              src={staticBadgeUrl({
+                baseUrl,
+                label: 'named logo',
+                message: name,
+                color: 'blue',
+                namedLogo: name,
               })}
             />
           </td>
           <td>
             <Badge
               alt={`logo: ${name}`}
-              src={staticBadgeUrl(baseUrl, 'Named Logo', name, 'blue', {
-                logo: name,
+              src={staticBadgeUrl({
+                baseUrl,
+                label: 'Named Logo',
+                message: name,
+                color: 'blue',
+                namedLogo: name,
                 style: 'social',
               })}
             />
diff --git a/frontend/components/dynamic-badge-maker.js b/frontend/components/dynamic-badge-maker.js
index 437dd9a5b1bb103e99605f7f7ff92ffdd29f397c..0eefa166c1dbc5ef4479cb01aaf000130f5e9203 100644
--- a/frontend/components/dynamic-badge-maker.js
+++ b/frontend/components/dynamic-badge-maker.js
@@ -1,6 +1,6 @@
 import React from 'react'
 import PropTypes from 'prop-types'
-import { dynamicBadgeUrl } from '../lib/badge-url'
+import { dynamicBadgeUrl } from '../../core/badge-urls/make-badge-url'
 import { InlineInput } from './common'
 
 export default class DynamicBadgeMaker extends React.Component {
@@ -11,7 +11,7 @@ export default class DynamicBadgeMaker extends React.Component {
   state = {
     datatype: '',
     label: '',
-    url: '',
+    dataUrl: '',
     query: '',
     color: '',
     prefix: '',
@@ -19,9 +19,22 @@ export default class DynamicBadgeMaker extends React.Component {
   }
 
   makeBadgeUrl() {
-    const { datatype, label, url, query, color, prefix, suffix } = this.state
+    const {
+      datatype,
+      label,
+      dataUrl,
+      query,
+      color,
+      prefix,
+      suffix,
+    } = this.state
     const { baseUrl: baseUrl = document.location.href } = this.props
-    return dynamicBadgeUrl(baseUrl, datatype, label, url, query, {
+    return dynamicBadgeUrl({
+      baseUrl: baseUrl || window.location.href,
+      datatype,
+      label,
+      dataUrl,
+      query,
       color,
       prefix,
       suffix,
@@ -34,8 +47,8 @@ export default class DynamicBadgeMaker extends React.Component {
   }
 
   get isValid() {
-    const { datatype, label, url, query } = this.state
-    return datatype && label && url && query
+    const { datatype, label, dataUrl, query } = this.state
+    return datatype && label && dataUrl && query
   }
 
   render() {
@@ -61,9 +74,9 @@ export default class DynamicBadgeMaker extends React.Component {
         />
         <InlineInput
           className="short"
-          onChange={event => this.setState({ url: event.target.value })}
-          placeholder="url"
-          value={this.state.url}
+          onChange={event => this.setState({ dataUrl: event.target.value })}
+          placeholder="data url"
+          value={this.state.dataUrl}
         />
         <InlineInput
           className="short"
diff --git a/frontend/components/footer.js b/frontend/components/footer.js
index 5a69f5b1f826bc8e8c4dd3bbceb300af9de96f54..a95d870ae5661390fc4e5b70cc20a706e98cd88e 100644
--- a/frontend/components/footer.js
+++ b/frontend/components/footer.js
@@ -1,7 +1,7 @@
 import React from 'react'
 import PropTypes from 'prop-types'
 import styled from 'styled-components'
-import resolveUrl from '../lib/resolve-url'
+import { badgeUrlFromPath } from '../../core/badge-urls/make-badge-url'
 import { H2 } from './common'
 
 const SpacedA = styled.a`
@@ -16,42 +16,55 @@ const Footer = ({ baseUrl }) => (
     <p>
       <object
         alt="Follow @shields_io"
-        data={resolveUrl(
-          '/twitter/follow/shields_io.svg?style=social&label=Follow',
-          baseUrl
-        )}
+        data={badgeUrlFromPath({
+          baseUrl,
+          path: '/twitter/follow/shields_io',
+          queryParams: { label: 'Follow' },
+          style: 'social',
+        })}
       />{' '}
       {}
       <object
         alt="Donate to us!"
-        data={resolveUrl(
-          '/opencollective/backers/shields.svg?style=social&link=https://opencollective.com/shields',
-          baseUrl
-        )}
+        data={badgeUrlFromPath({
+          baseUrl,
+          path: '/opencollective/backers/shields',
+          queryParams: { link: 'https://opencollective.com/shields' },
+          style: 'social',
+        })}
       />{' '}
       {}
       <object
         alt="Donate to us!"
-        data={resolveUrl(
-          '/opencollective/sponsors/shields.svg?style=social&link=https://opencollective.com/shields',
-          baseUrl
-        )}
+        data={badgeUrlFromPath({
+          baseUrl,
+          path: '/opencollective/sponsors/shields',
+          queryParams: { link: 'https://opencollective.com/shields' },
+          style: 'social',
+        })}
       />{' '}
       {}
       <object
         alt="Fork on GitHub"
-        data={resolveUrl(
-          '/github/forks/badges/shields.svg?style=social&label=Fork',
-          baseUrl
-        )}
+        data={badgeUrlFromPath({
+          baseUrl,
+          path: '/github/forks/badges/shields',
+          queryParams: { label: 'Fork' },
+          style: 'social',
+        })}
       />{' '}
       {}
       <object
         alt="chat on Discord"
-        data={resolveUrl(
-          '/discord/308323056592486420.svg?style=social&label=Chat&link=https://discord.gg/HjJCwm5',
-          baseUrl
-        )}
+        data={badgeUrlFromPath({
+          baseUrl,
+          path: '/discord/308323056592486420',
+          queryParams: {
+            label: 'Chat',
+            link: 'link=https://discord.gg/HjJCwm5',
+          },
+          style: 'social',
+        })}
       />
     </p>
 
diff --git a/frontend/components/static-badge-maker.js b/frontend/components/static-badge-maker.js
index 10db22f78d34dc6c7806b60c7196590fba58c652..8a9b8003a051615274bbb6b34a29043467c2835b 100644
--- a/frontend/components/static-badge-maker.js
+++ b/frontend/components/static-badge-maker.js
@@ -1,6 +1,6 @@
 import React from 'react'
 import PropTypes from 'prop-types'
-import { staticBadgeUrl } from '../lib/badge-url'
+import { staticBadgeUrl } from '../../core/badge-urls/make-badge-url'
 import { InlineInput } from './common'
 
 export default class StaticBadgeMaker extends React.Component {
@@ -9,8 +9,8 @@ export default class StaticBadgeMaker extends React.Component {
   }
 
   state = {
-    subject: '',
-    status: '',
+    label: '',
+    message: '',
     color: '',
   }
 
@@ -18,13 +18,13 @@ export default class StaticBadgeMaker extends React.Component {
     e.preventDefault()
 
     const { baseUrl } = this.props
-    const { subject, status, color } = this.state
-    const badgeUrl = staticBadgeUrl(
-      baseUrl || window.location.href,
-      subject,
-      status,
-      color
-    )
+    const { label, message, color } = this.state
+    const badgeUrl = staticBadgeUrl({
+      baseUrl: baseUrl || window.location.href,
+      label,
+      message,
+      color,
+    })
 
     document.location = badgeUrl
   }
@@ -33,14 +33,14 @@ export default class StaticBadgeMaker extends React.Component {
     return (
       <form onSubmit={e => this.handleSubmit(e)}>
         <InlineInput
-          onChange={event => this.setState({ subject: event.target.value })}
-          placeholder="subject"
-          value={this.state.subject}
+          onChange={event => this.setState({ label: event.target.value })}
+          placeholder="label"
+          value={this.state.label}
         />
         <InlineInput
-          onChange={event => this.setState({ status: event.target.value })}
-          placeholder="status"
-          value={this.state.status}
+          onChange={event => this.setState({ message: event.target.value })}
+          placeholder="message"
+          value={this.state.message}
         />
         <InlineInput
           list="default-colors"
diff --git a/frontend/components/suggestion-and-search.js b/frontend/components/suggestion-and-search.js
index 82a631f79d2c4ed262dd96b4740ce7e4a3be9807..dc98159c384ffd5b3edf8f2afd58b502b352bfa9 100644
--- a/frontend/components/suggestion-and-search.js
+++ b/frontend/components/suggestion-and-search.js
@@ -2,7 +2,6 @@ import React from 'react'
 import PropTypes from 'prop-types'
 import fetchPonyfill from 'fetch-ponyfill'
 import debounce from 'lodash.debounce'
-import resolveUrl from '../lib/resolve-url'
 import BadgeExamples from './badge-examples'
 import { BlockInput } from './common'
 
@@ -42,7 +41,7 @@ export default class SuggestionAndSearch extends React.Component {
       const { baseUrl } = this.props
       const { projectUrl } = this.state
 
-      const url = resolveUrl('/$suggest/v1', baseUrl, { url: projectUrl })
+      const url = `${baseUrl}/$suggest/v1?url=${encodeURIComponent(projectUrl)}`
 
       const fetch = window.fetch || fetchPonyfill
       const res = await fetch(url)
diff --git a/frontend/components/usage.js b/frontend/components/usage.js
index 4c54ea1d1745a65f6a15150ebb6a05c5a9044432..f323bfa2374adc27602386003c733c35a05e2be9 100644
--- a/frontend/components/usage.js
+++ b/frontend/components/usage.js
@@ -2,7 +2,7 @@ import React from 'react'
 import { Link } from 'gatsby'
 import PropTypes from 'prop-types'
 import styled from 'styled-components'
-import { staticBadgeUrl } from '../lib/badge-url'
+import { staticBadgeUrl } from '../../core/badge-urls/make-badge-url'
 import { advertisedStyles, shieldsLogos } from '../../supported-features.json'
 import StaticBadgeMaker from './static-badge-maker'
 import DynamicBadgeMaker from './dynamic-badge-maker'
@@ -69,7 +69,7 @@ const ColorExamples = ({ baseUrl, colors }) => (
       <Badge
         alt={color}
         key={color}
-        src={staticBadgeUrl(baseUrl, '', color, color)}
+        src={staticBadgeUrl({ baseUrl, label: '', message: color, color })}
       />
     ))}
   </span>
@@ -91,8 +91,12 @@ export default class Usage extends React.PureComponent {
         <tbody>
           {advertisedStyles.map(style => {
             const snippet = `?style=${style}&logo=appveyor`
-            const badgeUrl = staticBadgeUrl(baseUrl, 'style', style, 'green', {
-              logo: 'appveyor',
+            const badgeUrl = staticBadgeUrl({
+              baseUrl,
+              label: 'style',
+              message: style,
+              color: 'green',
+              namedLogo: 'appveyor',
               style,
             })
             return (
diff --git a/frontend/lib/badge-url.js b/frontend/lib/badge-url.js
deleted file mode 100644
index 5ff3aca4c72724823e28806d551eaf2c87e89974..0000000000000000000000000000000000000000
--- a/frontend/lib/badge-url.js
+++ /dev/null
@@ -1,53 +0,0 @@
-import resolveUrl from './resolve-url'
-import { staticBadgeUrl as makeStaticBadgeUrl } from '../../core/badge-urls/make-badge-url'
-
-export default function resolveBadgeUrl(
-  url,
-  baseUrl,
-  { longCache, style, queryParams: inQueryParams, format = 'svg' } = {}
-) {
-  const outQueryParams = Object.assign({}, inQueryParams)
-  if (longCache) {
-    outQueryParams.maxAge = '2592000'
-  }
-  if (style) {
-    outQueryParams.style = style
-  }
-
-  return resolveUrl(`${url}.${format}`, baseUrl, outQueryParams)
-}
-
-export function staticBadgeUrl(baseUrl, label, message, color, options) {
-  const path = makeStaticBadgeUrl({ label, message, color })
-  return resolveUrl(path, baseUrl, options)
-}
-
-// Options can include: { prefix, suffix, color, longCache, style, queryParams }
-export function dynamicBadgeUrl(
-  baseUrl,
-  datatype,
-  label,
-  dataUrl,
-  query,
-  { prefix, suffix, color, queryParams = {}, ...rest } = {}
-) {
-  Object.assign(queryParams, {
-    label,
-    url: dataUrl,
-    query,
-  })
-
-  if (color) {
-    queryParams.color = color
-  }
-  if (prefix) {
-    queryParams.prefix = prefix
-  }
-  if (suffix) {
-    queryParams.suffix = suffix
-  }
-
-  const outOptions = Object.assign({ queryParams }, rest)
-
-  return resolveBadgeUrl(`/badge/dynamic/${datatype}`, baseUrl, outOptions)
-}
diff --git a/frontend/lib/badge-url.spec.js b/frontend/lib/badge-url.spec.js
deleted file mode 100644
index 4817e4cb133c00516bb528b6b613759ceec679b1..0000000000000000000000000000000000000000
--- a/frontend/lib/badge-url.spec.js
+++ /dev/null
@@ -1,67 +0,0 @@
-import { test, given } from 'sazerac'
-import resolveBadgeUrl, { staticBadgeUrl, dynamicBadgeUrl } from './badge-url'
-
-const resolveBadgeUrlWithLongCache = (url, baseUrl) =>
-  resolveBadgeUrl(url, baseUrl, { longCache: true })
-
-describe('Badge URL functions', function() {
-  test(resolveBadgeUrl, () => {
-    given('/badge/foo-bar-blue', undefined).expect('/badge/foo-bar-blue.svg')
-    given('/badge/foo-bar-blue', 'http://example.com').expect(
-      'http://example.com/badge/foo-bar-blue.svg'
-    )
-  })
-
-  test(resolveBadgeUrlWithLongCache, () => {
-    given('/badge/foo-bar-blue', undefined).expect(
-      '/badge/foo-bar-blue.svg?maxAge=2592000'
-    )
-    given('/badge/foo-bar-blue', 'http://example.com').expect(
-      'http://example.com/badge/foo-bar-blue.svg?maxAge=2592000'
-    )
-  })
-
-  test(staticBadgeUrl, () => {
-    given('http://img.example.com', 'foo', 'bar', 'blue', {
-      style: 'plastic',
-    }).expect('http://img.example.com/badge/foo-bar-blue.svg?style=plastic')
-  })
-
-  test(dynamicBadgeUrl, () => {
-    const dataUrl = 'http://example.com/foo.json'
-    const query = '$.bar'
-    const prefix = 'value: '
-
-    given('http://img.example.com', 'json', 'foo', dataUrl, query, {
-      prefix,
-      style: 'plastic',
-    }).expect(
-      [
-        'http://img.example.com/badge/dynamic/json.svg',
-        '?label=foo',
-        `&url=${encodeURIComponent(dataUrl)}`,
-        `&query=${encodeURIComponent(query)}`,
-        `&prefix=${encodeURIComponent(prefix)}`,
-        '&style=plastic',
-      ].join('')
-    )
-
-    const suffix = '<- value'
-    const color = 'blue'
-    given('http://img.example.com', 'json', 'foo', dataUrl, query, {
-      suffix,
-      color,
-      style: 'plastic',
-    }).expect(
-      [
-        'http://img.example.com/badge/dynamic/json.svg',
-        '?label=foo',
-        `&url=${encodeURIComponent(dataUrl)}`,
-        `&query=${encodeURIComponent(query)}`,
-        '&color=blue',
-        `&suffix=${encodeURIComponent(suffix)}`,
-        '&style=plastic',
-      ].join('')
-    )
-  })
-})
diff --git a/frontend/lib/resolve-url.js b/frontend/lib/resolve-url.js
deleted file mode 100644
index f0f626ccbae2cbf12756a4e62fcafc372afbfa1f..0000000000000000000000000000000000000000
--- a/frontend/lib/resolve-url.js
+++ /dev/null
@@ -1,17 +0,0 @@
-// I played with build-url and url-resolve-browser and neither of them did the
-// right thing. Previously this was based on url-path, which patched around
-// the URL API. This caused problems in Firefox 57, but only in the production
-// build.
-
-// Let's rewrite these without a deprecated API!
-// eslint-disable-next-line node/no-deprecated-api
-import { resolve, parse, format } from 'url'
-
-// baseUrl and queryParams are optional.
-export default function resolveUrl(url, baseUrl, queryParams) {
-  const resolved = baseUrl ? resolve(baseUrl, url) : url
-  const parsed = parse(resolved, /* parseQueryString */ true)
-  parsed.query = Object.assign({}, parsed.query, queryParams)
-  delete parsed.search
-  return format(parsed)
-}
diff --git a/frontend/lib/resolve-url.spec.js b/frontend/lib/resolve-url.spec.js
deleted file mode 100644
index 25c5ffb9af3f8a1d24c4f6444217e57b2eb5f47e..0000000000000000000000000000000000000000
--- a/frontend/lib/resolve-url.spec.js
+++ /dev/null
@@ -1,29 +0,0 @@
-import { test, given, forCases } from 'sazerac'
-import resolveUrl from './resolve-url'
-
-describe('URL resolver', function() {
-  test(resolveUrl, () => {
-    forCases([
-      given('/foo/bar'),
-      given('/foo/bar', '/'),
-      given('/foo/bar', '/baz'),
-      given('/foo/bar', '/baz/'),
-      given('/foo/bar', ''),
-      given('/foo/bar', undefined),
-    ]).expect('/foo/bar')
-
-    given('foo/bar', '/baz/').expect('/baz/foo/bar')
-
-    forCases([
-      given('http://foo/bar'),
-      given('bar', 'http://foo/'),
-      given('/bar', 'http://foo/'),
-    ]).expect('http://foo/bar')
-
-    given('/foo/bar', '/baz', { baz: 'bazinga' }).expect('/foo/bar?baz=bazinga')
-
-    given('/foo/bar?thing=1', undefined, { other: '2' }).expect(
-      '/foo/bar?thing=1&other=2'
-    )
-  })
-})
diff --git a/frontend/pages/endpoint.js b/frontend/pages/endpoint.js
index f7a7f3f5e5e963b42aec5587c3c51dd31f0d2c71..5f35314c74463e272bee94df4a58c102e74d9bbb 100644
--- a/frontend/pages/endpoint.js
+++ b/frontend/pages/endpoint.js
@@ -1,7 +1,7 @@
 import React from 'react'
 import PropTypes from 'prop-types'
 import styled from 'styled-components'
-import { staticBadgeUrl } from '../lib/badge-url'
+import { staticBadgeUrl } from '../../core/badge-urls/make-badge-url'
 import { baseUrl } from '../constants'
 import Meta from '../components/meta'
 import Header from '../components/header'
@@ -101,7 +101,12 @@ const EndpointPage = () => (
     <p>Shields response:</p>
     <Badge
       alt="hello | sweet world"
-      src={staticBadgeUrl(baseUrl, 'hello', 'sweet world', 'orange')}
+      src={staticBadgeUrl({
+        baseUrl,
+        label: 'hello',
+        message: 'sweet world',
+        color: 'orange',
+      })}
     />
     <Explanation>
       <p>