Error while trying to access public stories from Medium API on client side


I'm trying to access Medium's API to get a list of public stories from a user. However, I'm getting a CORS error when I try to access it on the client side. Here's the code

axios.get(`http://medium.com/@ev/latest`).then((res)=>{ console.log(res.data) }) .catch((error)=>{ console.log(error) })

I did some research and found this <a href="https://github.com/Medium/medium-api-docs/issues/51" rel="nofollow">github issue</a>, but couldn't find any workaround. Is there any way to make this request work on the client side?


You can get the HTML from <a href="https://medium.com/@ev/latest" rel="nofollow">https://medium.com/@ev/latest</a> by making your request through a CORS proxy — either a proxy you set up yourself or else just by using a public open CORS proxy like <a href="https://cors-anywhere.herokuapp.com/" rel="nofollow">https://cors-anywhere.herokuapp.com/</a>. Here’s how to do it using the standard Fetch API:

<pre class="snippet-code-js lang-js prettyprint-override">fetch("https://cors-anywhere.herokuapp.com/https://medium.com/@ev/latest") .then(res => res.text()) .then(text => document.querySelector("div").innerHTML = text) .catch(error => console.log(error)) <pre class="snippet-code-html lang-html prettyprint-override"><script src="https://unpkg.com/axios/dist/axios.min.js"></script> <div></div>

For more details — including how to set up your own CORS proxy on Heroku in just a few minutes, see <em>How to use a CORS proxy to get around “No Access-Control-Allow-Origin header” problems</em> in the answer at <em><a href="https://stackoverflow.com/questions/43871637/no-access-control-allow-origin-header-is-present-on-the-requested-resource-whe/43881141#43881141" rel="nofollow">No 'Access-Control-Allow-Origin' header is present on the requested resource—when trying to get data from a REST API</a></em>.

<hr />

Incidentally, if instead you want JSON, you can try <a href="https://medium.com/@ev/latest?format=json" rel="nofollow">https://medium.com/@ev/latest?format=json</a> but you’ll find that what you get back isn’t actually valid JSON; instead it starts out like this:


Apparently that’s intentional, <a href="https://github.com/Medium/medium-api-docs/issues/51#issuecomment-267711057" rel="nofollow">per a comment from a Medium developer in their issue tracker</a>:


The JSON page is not intended to be used as a read API. The extra code is there to support our own use and is a standard technique to avoid JSON hijacking.


That’s trivial to work around, though: Just first handle the response as text in your client code, and strip out the ])}while(1);</x> from the start of it, and then run JSON.parse on what remains.

But as far as using Axios to get the response as text, I think you’ll find it’s not going to work as expected even if you make the request through a CORS proxy; try this:

<pre class="snippet-code-js lang-js prettyprint-override">axios.get('https://cors-anywhere.herokuapp.com/http://medium.com/@ev/latest', { responseType: 'text' }) .then(res => console.log(res.data)) .catch(error => console.log("ERROR")) <pre class="snippet-code-html lang-html prettyprint-override"><script src="https://unpkg.com/axios/dist/axios.min.js"></script>

The code hits the catch because apparently even when you specify responseType: 'text', <a href="https://github.com/axios/axios/issues/907#issuecomment-322054564" rel="nofollow">Axios apparently still tries the parse the response as JSON</a>:


This is because JSON.parse is always tried in the response, even if responseType is text. We should fix that indeed.


And <a href="https://medium.com/@ev/latest" rel="nofollow">https://medium.com/@ev/latest</a> is HTML, not JSON, so running JSON.parse on it will fail.

That’s why the first snippet in this answer uses the Fetch API instead (you can get text back with it).


This is currently not allowed by Medium (There server doesn't respond with the Access-Control-Allow-Origin header). Probably because of security concerns.

As suggested in the GitHub issue you linked to, a possible solution will be to tunnel the request to Medium through your server (as proxy). You can create an endpoint on your server (i.e. http://my-server.com/get-medium/@ev/latest) that will retrieve the requested Medium page (on the server side) and will return it to the client side.

This comment to the issue describes a way to do that using AWS Lambda as the proxy server - <a href="https://github.com/Medium/medium-api-docs/issues/51#issuecomment-278467906" rel="nofollow">link</a>


  • DART - exception in unit testing
  • jhipster oauth : How can i get the token via CURL
  • CORS issue with Vue.js
  • Does Angular 2 application block cookies from being stored by default?
  • multiple iron-collapse not working, expands only first
  • Which is performancewise better, check for class or add class [duplicate]
  • Sending HTML Form Multiple box via POST request with AJAX?
  • Why does this use of getImageData leak memory
  • Get highlight text in current window and send it in a popup
  • MVC extension method error
  • Angular - routerLinkActive and queryParams handling
  • How to get latest version of a artifact on Bintray using JSONP
  • Uncaught TypeError: $(…).select2 is not a function
  • How to view images from protected folder with php?
  • How do I get HTML corresponding to current DOM tree?
  • Display images in Django
  • JQuery Internet Explorer and ajaxstop
  • JSON response opens as a file, but I can't access it with JavaScript
  • FileReader+canvas image loading problem
  • DomPDF {PAGE_NUM} not on first page
  • Insert into database using onclick function
  • Deselecting radio buttons while keeping the View Model in synch
  • Javascript simulate pressing enter in input box
  • Why HTML5 Canvas with a larger size stretch a drawn line?
  • Resize panoramic image to fixed size
  • How to redirect a user to a different server and include HTTP basic authentication credentials?
  • MySQL WHERE-condition in procedure ignored
  • Can I make an Android app that runs a web view in Chrome 39?
  • Change an a tag attribute in JavaScript based on screen width
  • Importing jscolor library in angular 2
  • Web-crawler for facebook in python
  • A cron job substitute?
  • trying to dynamically update Highchart column chart but series undefined
  • IndexOutOfRangeException on multidimensional array despite using GetLength check
  • LevelDB C iterator
  • Linking SubReports Without LinkChild/LinkMaster
  • costura.fody for a dll that references another dll
  • Observable and ngFor in Angular 2
  • UserPrincipal.Current returns apppool on IIS
  • java string with new operator and a literal