Making a Chrome Extension download a file

I am creating an extension that will download a mp3 file off a website. I am trying to do this by creating a new tab with the link to the mp3 file, but chrome keeps opening it inside the player instead of downloading it. Is there any way I can create a pop-up to ask the user to "save-as" the file?


Fast-forward 3 years, and now Google Chrome offers chrome.downloads API (since Chrome 31).

After declaring "downloads" permission in the manifest, one can initiate a download with this call:

chrome.downloads.download({
  url: "http://your.url/to/download",
  filename: "suggested/filename/with/relative.path" // Optional
});

If you want to generate the file content in the script, you can use Blob and URL APIs, e.g.:

var blob = new Blob(["array of", " parts of ", "text file"], {type: "text/plain"});
var url = URL.createObjectURL(blob);
chrome.downloads.download({
  url: url // The object URL can be used as download URL
  //...
});

For more options (i.e. Save As dialog, overwriting existing files, etc.), see the documentation.


I used a variation on the solution here

var downloadCSS = function () {
    window.URL = window.webkitURL || window.URL;
    file = new BlobBuilder(); //we used to need to check for 'WebKitBlobBuilder' here - but no need anymore
    file.append(someTextVar); //populate the file with whatever text it is that you want
    var a = document.createElement('a');
    a.href = window.URL.createObjectURL(file.getBlob('text/plain'));
    a.download = 'combined.css'; // set the file name
    a.style.display = 'none';
    document.body.appendChild(a);
    a.click(); //this is probably the key - simulatating a click on a download link
    delete a;// we don't need this anymore
}

One thing you need to bare in mind is that this code needs to execute on the page and not your extension - otherwise the user won't see the download action that chrome does. The download will still happen and you will be able to see it in the download tab, but they won't see the actual download happen.

Edit (afterthought about making your code execute on the content page):

The way you make an action occur on the content page rather than your extension is to use Chrome "message passing". Basically, you pass a message from your extension (which is almost like a separate page) to the content page that the extension is working with. You then have a listener that your extension has injected into the content page that reacts to the message and does the download. Something like this:

chrome.extension.onMessage.addListener(
  function (request, sender, sendResponse) {  
      if (request.greeting == "hello") {
          try{
              downloadCSS();
          }
          catch (err) {
              alert("Error: "+err.message);
          }
      }
  });

This is a slightly modified version of @Steve Mc's answer that just makes it into a generalized function that can easily be copied and used as is:

function exportInputs() {
    downloadFileFromText('inputs.ini','dummy content!!')
}

function downloadFileFromText(filename, content) {
    var a = document.createElement('a');
    var blob = new Blob([ content ], {type : "text/plain;charset=UTF-8"});
    a.href = window.URL.createObjectURL(blob);
    a.download = filename;
    a.style.display = 'none';
    document.body.appendChild(a);
    a.click(); //this is probably the key - simulating a click on a download link
    delete a;// we don't need this anymore
}