Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
How to post a photo to Facebook from client-side Javascript
// This bit is important. It detects/adds XMLHttpRequest.sendAsBinary. Without this
// you cannot send image data as part of a multipart/form-data encoded request from
// Javascript. This implementation depends on Uint8Array, so if the browser doesn't
// support either XMLHttpRequest.sendAsBinary or Uint8Array, then you will need to
// find yet another way to implement this. (This is left as an exercise for the reader,
// but if you do it, please let me know and I'll integrate it.)
// from: http://stackoverflow.com/a/5303242/945521
if ( XMLHttpRequest.prototype.sendAsBinary === undefined ) {
XMLHttpRequest.prototype.sendAsBinary = function(string) {
var bytes = Array.prototype.map.call(string, function(c) {
return c.charCodeAt(0) & 0xff;
});
this.send(new Uint8Array(bytes).buffer);
};
}
// This function takes an array of bytes that are the actual contents of the image file.
// In other words, if you were to look at the contents of imageData as characters, they'd
// look like the contents of a PNG or GIF or what have you. For instance, you might use
// pnglib.js to generate a PNG and then upload it to Facebook, all from the client.
//
// Arguments:
// authToken - the user's auth token, usually from something like authResponse.accessToken
// filename - the filename you'd like the uploaded file to have
// mimeType - the mime type of the file, eg: image/png
// imageData - an array of bytes containing the image file contents
// message - an optional message you'd like associated with the image
function PostImageToFacebook( authToken, filename, mimeType, imageData, message )
{
// this is the multipart/form-data boundary we'll use
var boundary = '----ThisIsTheBoundary1234567890';
// let's encode our image file, which is contained in the var
var formData = '--' + boundary + '\r\n'
formData += 'Content-Disposition: form-data; name="source"; filename="' + filename + '"\r\n';
formData += 'Content-Type: ' + mimeType + '\r\n\r\n';
for ( var i = 0; i < imageData.length; ++i )
{
formData += String.fromCharCode( imageData[ i ] & 0xff );
}
formData += '\r\n';
formData += '--' + boundary + '\r\n';
formData += 'Content-Disposition: form-data; name="message"\r\n\r\n';
formData += message + '\r\n'
formData += '--' + boundary + '--\r\n';
var xhr = new XMLHttpRequest();
xhr.open( 'POST', 'https://graph.facebook.com/me/photos?access_token=' + authToken, true );
xhr.onload = xhr.onerror = function() {
console.log( xhr.responseText );
};
xhr.setRequestHeader( "Content-Type", "multipart/form-data; boundary=" + boundary );
xhr.sendAsBinary( formData );
}

nirleka commented May 9, 2012

I modified this code in:

xhr.open( 'POST', 'https://graph.facebook.com/'+albumId+'/photos?access_token=' + authToken, true );

//post to graph album

But the function return this error:

400 (Bad Request)
fb-album.js:120{
   "error": {
      "message": "(#1) An unknown error occurred",
      "type": "OAuthException",
      "code": 1
   }
}

Do you have any idea to fix this problems?
Thanks

Owner

andyburke commented May 9, 2012

I would check to make sure the authToken you're using gives permission to post to the given album.

coire1 commented Sep 15, 2012

Hi, i'm trying to use your code getting the image source from a HTML5 canvas element:
after generating image with canvas i convert it with

  source = img.toDataURL('image/png'); 

and upload it on Fb calling your function:

  PostImageToFacebook( accessToken, 'img.png', 'image/png', source, 'js upload' );

but the function return this error:

  400 (Bad Request)
  fbapp.js:439{
   "error": {
      "message": "(#1) An unknown error occurred",
      "type": "OAuthException",
      "code": 1
   }
  }

I'm sure that my authToken have the right permissions (i can do it in php!)
How can I fix it?
Thank you

jsalden commented Dec 13, 2012

Thanks Andy, this was very helpful!

coire1, I had the same "unknown error." In case you still need a solution, or for others who come across this, here's what worked for me:

You need to base64 decode the canvas output which can be done using this: https://github.com/danguer/blog-examples/blob/master/js/base64-binary.js

So my code ended up something like this:

var c = canvas.toDataURL('image/png');
var encodedPng = c.substring(c.indexOf(',')+1,c.length);
var decodedPng = Base64Binary.decode(encodedPng);

After that, I feed decodedPng into Andy's function, and it works great!

this is a great snippet, it seems ok on chrome but it fail on safari... can you help me?

I can confirm that it works on all decent browsers (i.e. all but IE), including Safari Mobile at iOS 5.1.
IE 9 (didn test 10) is the only one not supportting Uint8Array.

It is mandatory to use jsalden encoding/decoding approach.

Thanks a lot andyburke and jsalden. Doing this was the most hermetic stuff I've ever done in my developer career!!

hshhhhh commented Apr 11, 2013

thanks.

and some keywords for google: canvas upload photo facebook javascript javascriptsdk

coire1 commented Apr 12, 2013

I had give up hope. After 4 months i googled the same keywords, found this thread with my comment and....A SOLUTION!!! Wonderful! Thanks andyburke and jsalden!

hshhhhh commented Apr 13, 2013

lol

I am getting this. Can anybody help me out
[00:15:45.797] "{
"error": {
"message": "(#1) An unknown error occurred",
"type": "OAuthException",
"code": 1
}
}"

thanks, you saved me :)

    var img = document.createElement('img');
    img.src = 'http://localhost/quadrinhos/shareImage.png';
    img.onload = function () {
        var canvas = document.createElement("canvas"); 
        canvas.width = img.width; 
        canvas.height = img.height; 
        var ctx = canvas.getContext("2d"); 
        ctx.drawImage(img,0,0);
        var c = canvas.toDataURL('image/png');
        var encodedPng = c.substring(c.indexOf(',')+1,c.length);
        var decodedPng = Base64Binary.decode(encodedPng);

        PostImageToFacebook(response.authResponse.accessToken, 'shareImage.png', 'image/png', decodedPng, '');
    }

jarib commented Oct 9, 2015

This doesn't handle non-ASCII in the message part. Anyone know how to solve that?

I solved the charset problem using the following code in line 46:

formData += 'Content-Type: text/plain; charset=UTF-8\r\n';
formData += 'Content-Disposition: form-data; name="message"\r\n\r\n';
formData += unescape(encodeURIComponent(message)) + '\r\n'
formData += '--' + boundary + '--\r\n';

any one found a way to do this on IE9 ?

great snippet, it seems good for other browser but it fail on safari... can you help me?
getting this error:

------ThisIsTheBoundary1234567890--

photosPOST https://graph.facebook.com/me/photos?access_token=xyzzzzz 400 (Bad Request)
configurator:1440{
"error": {
"message": "(#324) Requires upload file",
"type": "OAuthException",
"code": 324,
"fbtrace_id": "C6NDlXMUwAy"
}
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment